Android立体旋转动画实现与封装(支持以X、Y、Z三个轴为轴心旋转)

本文主要介绍Android立体旋转动画,或者3D旋转,下图是我自己实现的一个界面

立体旋转分为以下三种:

1. 以X轴为轴心旋转

  2. 以Y轴为轴心旋转

  3. 以Z轴为轴心旋转--这种等价于android默认自带的旋转动画RotateAnimation

实现立体旋转核心步骤:

1. 继承系统Animation重写applyTransformation方法

    通过applyTransformation方法的回调参数 float interpolatedTime, Transformation t 来控制旋转动画

interpolatedTime 用来计算旋转角度而 用来控制变换矩阵从而实现图像的旋转

2. android.graphics.Camera控制旋转算法

Camera可以对图像执行一些比较复杂的操作--旋转,绽放,与Matrix一起实现图像的倾斜

核心代码封装:Rotate3dAnimation

package rotateanim.example.com.androidrotateanim;

import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.graphics.Camera;
import android.graphics.Matrix;

/**
 * An animation that rotates the view on the X,Y,Z axis between two specified angles.
 * This animation also adds a translation on the Z axis (depth) to improve the effect.
 */
public class Rotate3dAnimation extends Animation {
    public static final Byte ROTATE_X_AXIS = 0x00;
    public static final Byte ROTATE_Y_AXIS = 0x01;
    public static final Byte ROTATE_Z_AXIS = 0x02;
    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;
    private Byte mRotateAxis;  // 0:X轴  1:Y轴  2:Z轴

    /**创建3D旋转动画
     * @param fromDegrees the start angle of the 3D rotation
     * @param toDegrees the end angle of the 3D rotation
     * @param centerX the X center of the 3D rotation
     * @param centerY the Y center of the 3D rotation
     * @param depthZ the Z depth of the 3D rotation
     * @param rotateAxis the rotate axis of the 3D rotation
     * @param reverse true if the translation should be reversed, false otherwise
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees,
            float centerX, float centerY, float depthZ, Byte rotateAxis, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mRotateAxis = rotateAxis;
        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) {
            // z的偏移会越来越大。这就会形成这样一个效果,view从近到远
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            // z的偏移会越来越小。这就会形成这样一个效果,我们的View从一个很远的地方向我们移过来,越来越近,最终移到了我们的窗口上面
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        // 是给我们的View加上旋转效果,在移动的过程中,视图还会以XYZ轴为中心进行旋转。
        if (ROTATE_X_AXIS.equals(mRotateAxis)) {
            camera.rotateX(degrees);
        } else if (ROTATE_Y_AXIS.equals(mRotateAxis)) {
            camera.rotateY(degrees);
        } else {
            camera.rotateZ(degrees);
        }

        // 这个是将我们刚才定义的一系列变换应用到变换矩阵上面,调用完这句之后,我们就可以将camera的位置恢复了,以便下一次再使用。
        camera.getMatrix(matrix);
        // camera位置恢复
        camera.restore();

        // 下面两句是为了动画是以View中心为旋转点
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

Rotate3dAnimation使用:跟普通动画使用没区别,设置给一个View对象,启动动画就搞定

mRotateImgv就是需要旋转的View对象

// 以X轴为轴心旋转
private void rotateOnXCoordinate() {
    float centerX = mRotateImgv.getWidth() / 2.0f;
    float centerY = mRotateImgv.getHeight() / 2.0f;
    float depthZ = 0f;
    Rotate3dAnimation rotate3dAnimationX = new Rotate3dAnimation(0, 180, centerX, centerY, depthZ, Rotate3dAnimation.ROTATE_X_AXIS, true);
    rotate3dAnimationX.setDuration(1000);
    mRotateImgv.startAnimation(rotate3dAnimationX);
}

// 以X轴为轴心旋转
private void rotateOnYCoordinate() {
    float centerX = mRotateImgv.getWidth() / 2.0f;
    float centerY = mRotateImgv.getHeight() / 2.0f;
    float centerZ = 0f;

    Rotate3dAnimation rotate3dAnimationX = new Rotate3dAnimation(0, 180, centerX, centerY, centerZ, Rotate3dAnimation.ROTATE_Y_AXIS, true);
    rotate3dAnimationX.setDuration(1000);
    mRotateImgv.startAnimation(rotate3dAnimationX);
}

// 以Z轴为轴心旋转---等价于普通平面旋转动画
private void rotateAnimHorizon() {
    float centerX = mRotateImgv.getWidth() / 2.0f;
    float centerY = mRotateImgv.getHeight() / 2.0f;
    float centerZ = 0f;

    Rotate3dAnimation rotate3dAnimationX = new Rotate3dAnimation(180, 0, centerX, centerY, centerZ, Rotate3dAnimation.ROTATE_Z_AXIS, true);
    rotate3dAnimationX.setDuration(1000);
    mRotateImgv.startAnimation(rotate3dAnimationX);

    // 下面是使用android自带的旋转动画
    // RotateAnimation rotateAnimation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    // rotateAnimation.setDuration(1000);
    // mRotateImgv.startAnimation(rotateAnimation);
}

源码地址:https://github.com/PopFisher/AndroidRotateAnim

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python入门

十五道Python小案例,学会这些,Python基础已过关!

分析:可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去 掉不满足条件的排列。

3654
来自专栏移动开发之家

android 软软的动画弹出菜单,基于Facebook的Rebuond

︿( ̄︶ ̄)︿我是路过的DEMO : https://github.com/CarGuo/AnimationMenu

682
来自专栏算法+

3D Lut 电影级调色算法 附完整C代码

长话短说,3d lut(全称 : 3D Lookup table )它是通过建立一个颜色映射表,对图像的色调进行重调的算法。

66110
来自专栏章鱼的慢慢技术路

牛客网2018年全国多校算法寒假训练营练习比赛(第二场)

2204
来自专栏jeremy的技术点滴

python开发小技巧

2574
来自专栏算法+

图片文档倾斜矫正算法 附完整c代码

 2年前在学习图像算法的时候看到一个文档倾斜矫正的算法。 也就是说能将一些文档图像进行旋转矫正, 当然这个算法一般用于一些文档扫描软件做后处理 或者用于ocr ...

5855
来自专栏不止是前端

实用主义:JS判断给定日期是第几周

3157
来自专栏申龙斌的程序人生

零基础学编程014:小海龟做画

在《零基础学编程012:画出复利曲线图》这篇文章中,我们使用了强大的matplotlib和numpy模块,可以用几行代码画出复杂的图形来。但对于初学者来说,里面...

3077
来自专栏数据结构与算法

P2580 于是他错误的点名开始了

题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人。 他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次,然后正好被路过的校长发现了然后就是一顿欧拉欧拉...

2727
来自专栏ml

HDUOJ----2571(命运)(简单动态规划)

命运 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O...

2688

扫码关注云+社区