美文网首页
旋转动画Rotate3dAnimation

旋转动画Rotate3dAnimation

作者: 30cf443c3643 | 来源:发表于2018-09-12 10:47 被阅读91次

可直接参考matrix-3d-camera

在Android中如果想要实现3D效果一般有两种选择,一是使用Open GL ES,二是使用Camera。Open GL ES使用起来太过复杂,一般是用于比较高级的3D特效或游戏,像比较简单的一些3D效果,使用Camera就足够了。
Camera中提供了三种旋转方法,分别是rotateX()、rotateY()和rotateZ,调用这三个方法,并传入相应的角度,就可以让视图围绕这三个轴进行旋转

API Demos中已经给我们提供了一个非常好用的3D旋转动画的工具类Rotate3dAnimation

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;
    /**
     * 创建一个绕y轴旋转的3D动画效果,旋转过程中具有深度调节,可以指定旋转中心。
     * 
     * @param fromDegrees   起始时角度
     * @param toDegrees     结束时角度
     * @param centerX       旋转中心x坐标
     * @param centerY       旋转中心y坐标
     * @param depthZ        最远到达的z轴坐标
     * @param reverse       true 表示由从0到depthZ,false相反
     */
    public Rotate3dAnimation(Context context,float fromDegrees, float toDegrees,
            float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;

 // 获取手机像素密度 (即dp与px的比例)
        scale = context.getResources().getDisplayMetrics().density;
    }
   //只执行一次
    @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));
        }
      
        // 绕y轴旋转
        camera.rotateY(degrees);
      
        camera.getMatrix(matrix);
        camera.restore();

            // 修正失真,主要修改 MPERSP_0 和 MPERSP_1
        float[] mValues = new float[9];
        matrix.getValues(mValues);              //获取数值
        mValues[6] = mValues[6]/scale;          //数值修正
        mValues[7] = mValues[7]/scale;          //数值修正
        matrix.setValues(mValues);              //重新赋值

        // 调节中心点
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

代码的核心在applyTransformation方法里,需要了解Matrix以及camera的一些知识。

Matrix矩阵

坐标变换

基本的变换有:平移,旋转,缩放,错切。可以由矩阵控制


2018-09-11_172258.png

前乘(pre) 后乘(post)

前乘相当于矩阵的右乘:

M' = M*P

后乘相当于矩阵的左乘:

M' = P*M

矩阵不满足交换律,满足结合律

A * B ≠ B * A

使用 pre 和 post ?

2018-09-12_092007.png

所以可以看到Rotate3dAnimation 最后也有调节中心点的步骤

3D坐标系

2018-09-12_092546.png

android是左手坐标系,所以y轴的平移,2D跟3D是相反的

继承Animation

动画的具体实现是通过Animation中的getTransformation方法

public boolean getTransformation(long currentTime, Transformation outTransformation) {
        if (mStartTime == -1) {
            mStartTime = currentTime;
        }

        final long startOffset = getStartOffset();
        final long duration = mDuration;
        float normalizedTime;
        if (duration != 0) {
            normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
                    (float) duration;
        } else {
            // time is a step-change with a zero duration
            normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
        }

        final boolean expired = normalizedTime >= 1.0f || isCanceled();
        mMore = !expired;

        if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);

        if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
            if (!mStarted) {
                fireAnimationStart();
                mStarted = true;
                if (NoImagePreloadHolder.USE_CLOSEGUARD) {
                    guard.open("cancel or detach or getTransformation");
                }
            }

            if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);

            if (mCycleFlip) {
                normalizedTime = 1.0f - normalizedTime;
            }
             //通过插值器获得动画执行百分比
            final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);  
            applyTransformation(interpolatedTime, outTransformation);//应用动画效果
        }

      ...

        return mMore;
    }

applyTransformation是一个空实现。可以看看TranslateAnimation的实现

  @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float dx = mFromXDelta;
        float dy = mFromYDelta;
        if (mFromXDelta != mToXDelta) {
            dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
        }
        if (mFromYDelta != mToYDelta) {
            dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
        }
        t.getMatrix().setTranslate(dx, dy);
    }

大致也就理解了Animation的子类该如何写

相关文章

网友评论

      本文标题:旋转动画Rotate3dAnimation

      本文链接:https://www.haomeiwen.com/subject/fusugftx.html