标签:
在源码中,这段是申请空间大小的,为那些子控件,不然你出现就没有地方显示了. @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