答案 0 :(得分:1)
看看这堂课。它应该按你的意愿工作:
public class CircleLayout extends ViewGroup {
private static final float DEFAULT_FROM_DEGREES = -90f;
private static final float DEFAULT_TO_DEGREES = 270f;
private static final int MIN_RADIUS_DP = 100;
private static final float DEFAULT_CHILD_PADDING_DP = 5f;
private final Rect tempChildFrame = new Rect();
private final float fromDegrees;
private final float toDegrees;
private final int childPadding;
private final int minRadius;
private int radius;
private int childSize;
private boolean expanded;
public CircleLayout(Context context) {
this(context, null);
}
public CircleLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleLayout(Context context, AttributeSet attrs, int def) {
super(context, attrs);
final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircleLayout, 0, 0);
try {
childSize = Math.max(a.getDimensionPixelSize(R.styleable.CircleLayout_childSize, 0), 0);
fromDegrees = a.getFloat(R.styleable.CircleLayout_fromDegrees, DEFAULT_FROM_DEGREES);
toDegrees = a.getFloat(R.styleable.CircleLayout_toDegrees, DEFAULT_TO_DEGREES);
final float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CHILD_PADDING_DP, getResources().getDisplayMetrics());
childPadding = (int) a.getDimension(R.styleable.CircleLayout_childPadding, px);
expanded = a.getBoolean(R.styleable.CircleLayout_expandedChild, true);
minRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, MIN_RADIUS_DP, getResources().getDisplayMetrics());
} finally {
a.recycle();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
radius = computeRadius(Math.abs(toDegrees - fromDegrees), getChildCount(), childSize, childPadding, minRadius);
final int size = radius * 2 + childSize + childPadding;
setMeasuredDimension(size + getPaddingLeft() + getPaddingRight(), size + getPaddingTop() + getPaddingBottom());
final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY));
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int centerX = getWidth() / 2;
final int centerY = getHeight() / 2;
final int radius = expanded ? this.radius : 0;
final int childCount = getChildCount();
final float perDegrees = (toDegrees - fromDegrees) / childCount;
float degrees = fromDegrees;
for (int i = 0; i < childCount; i++) {
computeChildFrame(centerX, centerY, radius, degrees, childSize, tempChildFrame);
degrees += perDegrees;
getChildAt(i).layout(tempChildFrame.left, tempChildFrame.top, tempChildFrame.right, tempChildFrame.bottom);
}
}
private int computeRadius(float arcDegrees, int childCount, int childSize, int childPadding, int minRadius) {
if (childCount < 2) {
return minRadius;
}
final float perDegrees = arcDegrees / childCount;
final float perHalfDegrees = perDegrees / 2;
final int perSize = childSize + childPadding;
final int radius = (int) ((perSize / 2) / Math.sin(Math.toRadians(perHalfDegrees)));
return Math.max(radius, minRadius);
}
private void computeChildFrame(int centerX, int centerY, int radius, float degrees, int size, Rect result) {
final double childCenterX = centerX + radius * Math.cos(Math.toRadians(degrees));
final double childCenterY = centerY + radius * Math.sin(Math.toRadians(degrees));
final float halfSize = size * .5f;
result.left = (int) (childCenterX - halfSize);
result.top = (int) (childCenterY - halfSize);
result.right = (int) (childCenterX + halfSize);
result.bottom = (int) (childCenterY + halfSize);
}
public void expand() {
expanded = true;
requestLayout();
}
public void shrink() {
expanded = false;
requestLayout();
}
public void setChildSize(int size) {
if (childSize == size || size < 0) {
return;
}
childSize = size;
requestLayout();
}
public boolean isExpanded() {
return expanded;
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
final SavedState result = new SavedState(superState);
result.childSize = childSize;
result.expanded = expanded;
return result;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
final SavedState ss = (SavedState) state;
childSize = ss.childSize;
expanded = ss.expanded;
super.onRestoreInstanceState(ss.getSuperState());
}
public static class SavedState extends BaseSavedState {
@SuppressWarnings("hiding")
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
private int childSize;
private boolean expanded;
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(childSize);
out.writeInt(expanded ? 1 : 0);
}
private SavedState(Parcel in) {
super(in);
childSize = in.readInt();
expanded = in.readInt() != 0;
}
}
}
您还必须为此视图添加样式:
<declare-styleable name="CircleLayout">
<attr name="childSize" format="dimension"/>
<attr name="childPadding" format="dimension"/>
<attr name="fromDegrees" format="integer"/>
<attr name="toDegrees" format="integer"/>
<attr name="expandedChild" format="boolean"/>
</declare-styleable>
使用示例:
<your.package.CircleLayout
android:clipChildren="false"
android:id="@+id/test_circle_view"
android:layout_width="match_parent"
app:childSize="50dp"
app:childPadding="25dp"
app:expandedChild="true"
android:layout_height="match_parent">
<ImageView
android:id="@+id/circle_item_1"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/some_circle"/>
<ImageView
android:id="@+id/circle_item_2"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/some_circle"/>
<ImageView
android:id="@+id/circle_item_3"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/some_circle"/>
<ImageView
android:id="@+id/circle_item_4"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/some_circle"/>
<ImageView
android:id="@+id/circle_item_5"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/some_circle"/>
<ImageView
android:id="@+id/circle_item_6"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/some_circle"/>
</your.package.CircleLayout>
答案 1 :(得分:1)
问题的确切解决方案是使用 ConstraintLayout中的循环定位 ,有关它的更多信息,您可以点击此链接: https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html#CircularPositioning
希望这可以完全解决您的问题,从而帮助您构建所需的用户界面。