在源码中,这段是申请空间大小的,为那些子控件,不然你出现就没有地方显示了.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int radius = mRadius = mSetRadius == -1 ? computeRadius(
Math.abs(mToDegrees - mFromDegrees), getChildCount(),
mChildSize, mChildPadding, MIN_RADIUS) : mSetRadius;
final int size = radius * 2 + mChildSize + mChildPadding
+ mLayoutPadding * 2;
setMeasuredDimension(size, size);
final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i)
.measure(
MeasureSpec.makeMeasureSpec(mChildSize,
MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mChildSize,
MeasureSpec.EXACTLY));
}
}
这段代码是当动画后,requestlayout 就触发这个,让子控件显示在真正的位置上.
原来这里 getheight()/2的,我改成了 gethe... ,是为了将控件放在最下面,才能形成
从最下面出来的效果.
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int centerX = getWidth() / 2;
final int centerY = getHeight();
final int radius = mExpanded ? mRadius : 0; // 如果半径为0,回到了中心点.
final int childCount = getChildCount();
final float perDegrees = (mToDegrees - mFromDegrees) / (childCount - 1);
float degrees = mFromDegrees; // 角度.
for (int i = 0; i < childCount; i++) {
Rect frame = computeChildFrame(centerX, centerY, radius, degrees,
mChildSize);
degrees += perDegrees;
getChildAt(i).layout(frame.left, frame.top, frame.right,
frame.bottom);
}
}
@SuppressLint("NewApi")
private void bindChildAnimation(final View child, final int index,
final long duration) {
/**
* true : 回来. false : 出去.
*/
final boolean expanded = mExpanded; // 弹出,弹进的动画旋转.
final int centerX = getWidth() / 2;
final int centerY = getHeight();
final int radius = expanded ? 0 : mRadius;
final int childCount = getChildCount();
// (360 - 180) / (5 - 1) = 45 度 !! 如果这里是5个的话,还是可以到达中心点的,如果6,7,这里需要改为45.
final float perDegrees = (mToDegrees - mFromDegrees) / (childCount - 1);
Rect frame;
if (!expanded) {
frame = computeChildFrame(centerX, centerY, radius, mFromDegrees
+ index * perDegrees, mChildSize); // 计算需要移动过去的位置.
} else {
frame = computeChildFrame(centerX, centerY, mRadius, mFromDegrees
+ (270 - mFromDegrees), mChildSize); // 计算需要移动过去的位置.
}
//
Rect framedown = computeChildFrame(centerX, centerY, 0, mFromDegrees
+ (270 - mFromDegrees), mChildSize); // 计算需要移动过去的位置.
//
final int toXDelta = frame.left - child.getLeft(); // 用准备移动的left -
// 控件原始的left.
final int toYDelta = frame.top - child.getTop(); //
Interpolator interpolator = mExpanded ? new AccelerateInterpolator()
: new OvershootInterpolator(1.5f); // 加速器.
final long startOffset = computeStartOffset(childCount, mExpanded,
index, 0.1f, duration, interpolator); //
// 旋转动画. createShrinkAnimation 缩回去的动画,反之.
Animation animation = mExpanded ? createShrinkAnimation(0, toXDelta, 0,
toYDelta, startOffset, duration + 300, interpolator, framedown)
: createExpandAnimation(0, toXDelta, 0, toYDelta, startOffset,
duration, interpolator); // 动画效果.
if (mExpanded) {
this.cb.onSwitchGone();
} else {
this.cb.onSwitchVisible();
}
final boolean isLast = getTransformedIndex(expanded, childCount, index) == childCount - 1;
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (isLast) {
postDelayed(new Runnable() {
@Override
public void run() {
onAllAnimationsEnd();
}
}, 0);
}
}
});
child.setAnimation(animation); // 设置动画.
}
然后再修改角度. 当外部的 toDegrees, mFromDegrees 进行加减的时候,就开始旋转了.
public void setArc(float fromDegrees, float toDegrees,
ArcMenuDegreesCallBack cb) {
if (mFromDegrees == fromDegrees && mToDegrees == toDegrees) {
return;
}
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
requestLayout(); //
if (cb != null)
cb.onLastDegrees();
}
原文:http://my.oschina.net/hailongqiu/blog/401573