【问题标题】:Create 3D animtation for Android Apps为 Android 应用程序创建 3D 动画
【发布时间】:2016-11-02 12:18:03
【问题描述】:

我需要根据用户在屏幕上滑动的速度创建 3D 翻转/旋转动画,我可以使用 ObjectAnimator 及其相关属性创建此动画,但我需要建议如何创建 3D上面的android中的动画。我还需要执行一些部分旋转的动画

虽然对于 android 我们可以使用 OPENGL,但是对于简单的动画 OPENGL 太重了,因为我们不是在设计真正的游戏。我参考了以下链接:

【问题讨论】:

    标签: android animation 3d objectanimator animatorset


    【解决方案1】:

    试试这个

    MainActivity.java

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.layout_main, ExampleFragment.newInstance(ExampleFragment.NODIR));
        ft.commit();
    }
    

    ExampleFragment.java

    public class ExampleFragment extends Fragment {
    
        @IntDef({NONE, FLIP})
        public @interface AnimationStyle {}
        public static final int NONE     = 0;
        public static final int FLIP     = 2;
    
        @IntDef({NODIR, UP, DOWN, LEFT, RIGHT})
        public @interface AnimationDirection {}
        public static final int NODIR = 0;
        public static final int UP    = 1;
        public static final int DOWN  = 2;
        public static final int LEFT  = 3;
        public static final int RIGHT = 4;
    
        private static final long DURATION = 500;
    
        @AnimationStyle
        private static int sAnimationStyle = FLIP;
    
        public static ExampleFragment newInstance(@AnimationDirection int direction) {
            ExampleFragment f = new ExampleFragment();
            f.setArguments(new Bundle());
            f.getArguments().putInt("direction", direction);
            return f;
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.content_anim, null);
    
            // For generating random Colors
            int color = Color.rgb((int) Math.floor(Math.random() * 128) + 64,
                    (int) Math.floor(Math.random() * 128) + 64,
                    (int) Math.floor(Math.random() * 128) + 64);
            view.setBackgroundColor(color);
    
            ButterKnife.bind(this, view);
            return view;
        }
    
    
    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        switch (sAnimationStyle) {
            case FLIP:
                switch (getArguments().getInt("direction")) {
                    case UP:
                        return FlipAnimation.create(FlipAnimation.UP, enter, DURATION);
                    case DOWN:
                        return FlipAnimation.create(FlipAnimation.DOWN, enter, DURATION);
                    case LEFT:
                        return FlipAnimation.create(FlipAnimation.LEFT, enter, DURATION);
                    case RIGHT:
                        return FlipAnimation.create(FlipAnimation.RIGHT, enter, DURATION);
                }
                break;
        }
        return null;
    }
    
    
        @OnClick(R.id.buttonUp)
        void onButtonUp() {
            getArguments().putInt("direction", UP);
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.layout_main, ExampleFragment.newInstance(UP));
            ft.commit();
        }
    
        @OnClick(R.id.buttonDown)
        void onButtonDown() {
            getArguments().putInt("direction", DOWN);
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.layout_main, ExampleFragment.newInstance(DOWN));
            ft.commit();
        }
    
        @OnClick(R.id.buttonLeft)
        void onButtonLeft() {
            getArguments().putInt("direction", LEFT);
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.layout_main, ExampleFragment.newInstance(LEFT));
            ft.commit();
        }
    
        @OnClick(R.id.buttonRight)
        void onButtonRight() {
            getArguments().putInt("direction", RIGHT);
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.layout_main, ExampleFragment.newInstance(RIGHT));
            ft.commit();
        }
    }
    

    FlipAnimation.java

    public class FlipAnimation extends ViewPropertyAnimation {
    
        @IntDef({UP, DOWN, LEFT, RIGHT})
        @interface Direction {}
        public static final int UP    = 1;
        public static final int DOWN  = 2;
        public static final int LEFT  = 3;
        public static final int RIGHT = 4;
    
        protected final @Direction int mDirection;
        protected final boolean mEnter;
    
        public static FlipAnimation create(@Direction int direction, boolean enter, long duration) {
            switch (direction) {
                case UP:
                case DOWN:
                    return new VerticalFlipAnimation(direction, enter, duration);
                case LEFT:
                case RIGHT:
                    return new HorizontalFlipAnimation(direction, enter, duration);
            }
            return null;
        }
    
        private FlipAnimation(@Direction int direction, boolean enter, long duration) {
            mDirection = direction;
            mEnter = enter;
            setDuration(duration);
        }
    
        private static class VerticalFlipAnimation extends FlipAnimation {
    
            public VerticalFlipAnimation(@Direction int direction, boolean enter, long duration) {
                super(direction, enter, duration);
            }
    
            @Override
            public void initialize(int width, int height, int parentWidth, int parentHeight) {
                super.initialize(width, height, parentWidth, parentHeight);
                mPivotX = width * 0.5f;
                mPivotY = (mEnter == (mDirection == UP)) ? 0.0f : height;
                mCameraZ = -height * 0.015f;
            }
    
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                float value = mEnter ? (interpolatedTime - 1.0f) : interpolatedTime;
                if (mDirection == DOWN) value *= -1.0f;
                mRotationX = value * 180.0f;
                mTranslationY = -value * mHeight;
    
                super.applyTransformation(interpolatedTime, t);
    
                // Hide exiting view after half point.
                if (interpolatedTime >= 0.5f && !mEnter) {
                    mAlpha = 0.0f;
                }
                applyTransformation(t);
            }
        }
    
        private static class HorizontalFlipAnimation extends FlipAnimation {
    
            public HorizontalFlipAnimation(@Direction int direction, boolean enter, long duration) {
                super(direction, enter, duration);
            }
    
            @Override
            public void initialize(int width, int height, int parentWidth, int parentHeight) {
                super.initialize(width, height, parentWidth, parentHeight);
                mPivotX = (mEnter == (mDirection == LEFT)) ? 0.0f : width;
                mPivotY = height * 0.5f;
                mCameraZ = -width * 0.015f;
            }
    
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                float value = mEnter ? (interpolatedTime - 1.0f) : interpolatedTime;
                if (mDirection == RIGHT) value *= -1.0f;
                mRotationY = -value * 180.0f;
                mTranslationX = -value * mWidth;
    
                super.applyTransformation(interpolatedTime, t);
    
                // Hide exiting view after half point.
                if (interpolatedTime >= 0.5f && !mEnter) {
                    mAlpha = 0.0f;
                }
                applyTransformation(t);
            }
        }
    }
    

    ViewPropertyAnimation.java

    public class ViewPropertyAnimation extends Animation {
    
        private final Camera mCamera = new Camera();
        protected int mWidth  = 0;
        protected int mHeight = 0;
        protected float mAlpha = 1.0f;
        protected float mPivotX = 0.0f;
        protected float mPivotY = 0.0f;
        protected float mScaleX = 1.0f;
        protected float mScaleY = 1.0f;
        protected float mRotationX = 0.0f;
        protected float mRotationY = 0.0f;
        protected float mRotationZ = 0.0f;
        protected float mTranslationX = 0.0f;
        protected float mTranslationY = 0.0f;
        protected float mTranslationZ = 0.0f;
        protected float mCameraX = 0.0f;
        protected float mCameraY = 0.0f;
        protected float mCameraZ = -8.0f;
    
        private float mFromAlpha = -1.0f;
        private float mToAlpha   = -1.0f;
    
        public ViewPropertyAnimation fading(@FloatRange(from=0.0f,to=1.0f) float fromAlpha, @FloatRange(from=0.0f,to=1.0f) float toAlpha) {
            mFromAlpha = fromAlpha;
            mToAlpha = toAlpha;
            return this;
        }
    
        @Override
        public void initialize(int width, int height, int parentWidth, int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
            mWidth = width;
            mHeight = height;
        }
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (mFromAlpha >= 0 && mToAlpha >= 0) {
                mAlpha = mFromAlpha + (mToAlpha - mFromAlpha) * interpolatedTime;
            }
        }
    
        protected void applyTransformation(Transformation t) {
            final Matrix m = t.getMatrix();
            final float w = mWidth;
            final float h = mHeight;
            final float pX = mPivotX;
            final float pY = mPivotY;
    
            final float rX = mRotationX;
            final float rY = mRotationY;
            final float rZ = mRotationZ;
            if ((rX != 0) || (rY != 0) || (rZ != 0)) {
                final Camera camera = mCamera;
                camera.save();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
                    camera.setLocation(mCameraX, mCameraY, mCameraZ);
                }
                if (mTranslationZ != 0) {
                    camera.translate(0, 0, mTranslationZ);
                }
                camera.rotateX(rX);
                camera.rotateY(rY);
                camera.rotateZ(-rZ);
                camera.getMatrix(m);
                camera.restore();
                m.preTranslate(-pX, -pY);
                m.postTranslate(pX, pY);
            }
    
            final float sX = mScaleX;
            final float sY = mScaleY;
            if ((sX != 1.0f) || (sY != 1.0f)) {
                m.postScale(sX, sY);
                final float sPX = -(pX / w) * ((sX * w) - w);
                final float sPY = -(pY / h) * ((sY * h) - h);
                m.postTranslate(sPX, sPY);
            }
    
            m.postTranslate(mTranslationX, mTranslationY);
    
            t.setAlpha(mAlpha);
        }
    }
    

    【讨论】:

    • 我需要它从中心旋转,当它 90* 时它必须有厚度
    • 所以你想要的效果和你在question??中给出的效果一样?
    • 是的,翻转/旋转必须从中心发生(我已经管理过了),但它没有 3D 效果
    • @Mashukhan 当它是 90 度时我们怎么能有宽度
    • 查看我的更新答案。您可以通过将mRotationXmRotationY 的乘积值从 90.0f 更改为 180.0f 来获得宽度。并添加下面的代码来覆盖方法applyTransformation 这隐藏了半点后的退出视图if (interpolatedTime >= 0.5f && !mEnter) { mAlpha = 0.0f; }
    【解决方案2】:

    其实你已经提到了:

    基于用户在屏幕上滑动的速度的 3D 翻转/旋转动画

    所以,我认为 Android Animation 不适合您的情况。但如果您有自定义视图方面的经验,android.graphics.Camera 中的类会帮助您。

    首先,你需要声明

    camera = new Camera();
    

    然后覆盖 OnDraw 。

    canvas.save();
    Matrix matrix = new Matrix(); 
    camera.save();
    camera.rotateY(rotateAngle);
    camera.getMatrix(matrix);
    camera.restore();
    
    mPaint.setColor(textBackgroundColor);
    int centerX = diameter / 2;
    int centerY = diameter / 2;
    matrix.preTranslate(-centerX, -centerY);
    matrix.postTranslate(centerX, centerY);
    canvas.concat(matrix);
    canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, mPaint);
    canvas.restore();
    

    现在您可以看到我们围绕 y 轴旋转了一个圆 rotateAngle 度数。您可以更改 rotateAngle 的值来调整角度。

    你可以参考我最新的文章here,源码在github link

    【讨论】:

      猜你喜欢
      • 2020-05-02
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-18
      相关资源
      最近更新 更多