美文网首页
旋转动画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