標籤:
在源碼中,這段是申請空間大小的,為那些子控制項,不然你出現就沒有地方顯示了.@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(); }
ArcMenu如何去修改類似小米的系統功能表