Rotating FloatingActionButton

前端 未结 2 1940
臣服心动
臣服心动 2021-01-26 15:36

I believe most of you all have seen the rotating FloatingActionButton in apps such as Google keep, push bullet and even Google inbox app. I am trying to achieve this rotation by

相关标签:
2条回答
  • 2021-01-26 16:16

    Yes...what you have to do is to rotate the mActionIcon in FloatingActionButtonClass . See below.

       public void applyRotation(float start, float end, final int imgRes) {
        final float centerX = getWidth() / 2.0f;
        final float centerY = getHeight() / 2.0f;
    
        // The animation listener is used to trigger the next animation
        final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end,
                centerX, centerY, 0, true);
        rotation.setDuration(100);
        rotation.setFillAfter(true);
        rotation.setInterpolator(new AccelerateInterpolator());
    
        rotation.setAnimationListener(new AnimationListener() {
    
            @Override
            public void onAnimationStart(Animation animation) {
    
            }
    
            @Override
            public void onAnimationRepeat(Animation animation) {
    
            }
    
            @Override
            public void onAnimationEnd(Animation animation) {
                mActionIcon = getResources().getDrawable(imgRes);
                mActionIcon.setBounds(0, 0, mActionSize, mActionSize);
                // invalidate();
                rotateSecondImage(-45, 0);
            }
    
        });
    
        startAnimation(rotation);
    
    }
    
    
    private void rotateSecondImage(float start, float end) {
        final float centerX = getWidth() / 2.0f;
        final float centerY = getHeight() / 2.0f;
    
        // The animation listener is used to trigger the next animation
        final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end,
                centerX, centerY, 0, true);
        rotation.setDuration(100);
        rotation.setFillAfter(true);
        rotation.setInterpolator(new DecelerateInterpolator());
        startAnimation(rotation);
    }
    
    
    public class Rotate3dAnimation extends Animation {
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private final float mDepthZ;
    private final boolean mReverse;
    private Camera mCamera;
    
    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX,
            float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
    }
    
    @Override
    public void initialize(int width, int height, int parentWidth,
            int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }
    
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees
                + ((mToDegrees - fromDegrees) * interpolatedTime);
    
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
    
        final Matrix matrix = t.getMatrix();
    
        camera.save();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateZ(degrees);
        camera.getMatrix(matrix);
        camera.restore();
    
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
    

    }

    0 讨论(0)
  • 2021-01-26 16:16

    I found that on pre-Lollipop shadow is rotating, but on API >= 21 everything is right.

    So, on pre-Lollipop I've tried to rotate an ImageView over FAB. And it works great.

    Here is layout where we place ImageView with same source image over FAB:

    <FrameLayout>
        android:id="@+id/rotatingFab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end">
    
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:src="@drawable/ic_autorenew_white_24dp"/>
    
        <ImageView
            android:id="@+id/fabImage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@color/accent"
            android:src="@drawable/ic_autorenew_white_24dp"
            android:visibility="gone"/>
    
    </FrameLayout>
    

    We start animation like this:

    public void startAnimation(Animation animation) {
        if (Build.VERSION.SDK_INT >= 21) {
            mFab.startAnimation(animation);
        } else {
            mFabImage.setVisibility(VISIBLE);
            // need post() to image could measure its size
            mFabImage.post(() -> mFabImage.startAnimation(animation));
        }
    }
    

    And stop it:

    public void clearAnimation() {
        if (Build.VERSION.SDK_INT >= 21) {
            mFab.clearAnimation();
        } else {
            mFabImage.clearAnimation();
            mFabImage.setVisibility(GONE);
        }
    }
    

    I wrap FrameLayout in custom view to more comfortable, here is full gist https://gist.github.com/pengrad/9db82de705b58b10c5e9

    0 讨论(0)
提交回复
热议问题