【问题标题】:Creating a 3D flip animation in Android using XML使用 XML 在 Android 中创建 3D 翻转动画
【发布时间】:2011-10-16 16:25:48
【问题描述】:

我使用this android tutorial 创建了视图的 3D 翻转 但是,我已经以编程方式完成了它,如果可能的话,我想在 xml 中完成这一切。我说的不是简单地将视图缩小到中间然后退出,而是实际的 3D 翻转。

这可以通过 xml 实现吗?

【问题讨论】:

    标签: android xml animation 3d


    【解决方案1】:

    这是答案,尽管它仅适用于 3.0 及更高版本。

    1) 创建一个名为“animator”的新资源文件夹。

    2) 创建一个新的 .xml 文件,我将其称为“翻转”。使用以下 xml 代码:

    <?xml version="1.0" encoding="utf-8"?>
    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:valueFrom="0" android:valueTo="360" android:propertyName="rotationY" >
    </objectAnimator>
    

    不,objectAnimator 标签不以大写“O”开头。

    3) 使用以下代码启动动画:

    ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator(mContext, R.animator.flipping); 
    anim.setTarget(A View Object reference goes here i.e. ImageView);
    anim.setDuration(3000);
    anim.start();
    

    这一切都是从here 那里得到的。

    【讨论】:

    • @RAS 感谢您提供图书馆的链接。 :) 也许下次它可以进入 cmets 而不是编辑我的答案?我对这个库一无所知,所以把它归于我是不太正确的。不过感谢您的意见!
    • 我理解你的观点,没有人喜欢未经他/她许可的人编辑他/她的帖子。但是这个答案不是我编辑的。它是由其他人编辑的,我刚刚批准它并解决了编辑您的答案的那个人所犯的语法错误。如果您想查看它,请单击我的姓名和徽标上方“已编辑”旁边显示的日期/时间。您可以在那里查看完整的修订历史记录。
    • 要在 3.0 以下使用此代码,请使用以下库:github.com/JakeWharton/NineOldAndroids。用户贡献:stackoverflow.com/users/1117511/loks
    • @KrunalShah 其实只需在 objectAnimator 声明中添加 android:valueFrom="0" 即可解决问题。
    • 这导致了一个相当幼稚的翻转,应该实现一些缩放以使其更具视觉吸引力。
    【解决方案2】:

    由于这个问题的答案已经过时,这里有一个更现代的解决方案,它依赖于 ValueAnimators。 这个解决方案实现了一个真正的、视觉上吸引人的 3D 翻转,因为它不仅翻转视图,而且在翻转的同时对其进行缩放(Apple 就是这样做的)。

    首先我们设置 ValueAnimator:

    mFlipAnimator = ValueAnimator.ofFloat(0f, 1f);
    mFlipAnimator.addUpdateListener(new FlipListener(frontView, backView));
    

    以及对应的更新监听器:

    public class FlipListener implements ValueAnimator.AnimatorUpdateListener {
    
        private final View mFrontView;
        private final View mBackView;
        private boolean mFlipped;
    
        public FlipListener(final View front, final View back) {
            this.mFrontView = front;
            this.mBackView = back;
            this.mBackView.setVisibility(View.GONE);
        }
    
        @Override
        public void onAnimationUpdate(final ValueAnimator animation) {
            final float value = animation.getAnimatedFraction();
            final float scaleValue = 0.625f + (1.5f * (value - 0.5f) * (value - 0.5f));
    
            if(value <= 0.5f){
                this.mFrontView.setRotationY(180 * value);
                this.mFrontView.setScaleX(scaleValue);
                this.mFrontView.setScaleY(scaleValue);
                if(mFlipped){
                    setStateFlipped(false);
                }
            } else {
                this.mBackView.setRotationY(-180 * (1f- value));
                this.mBackView.setScaleX(scaleValue);
                this.mBackView.setScaleY(scaleValue);
                if(!mFlipped){
                    setStateFlipped(true);
                }
            }
        }
    
        private void setStateFlipped(boolean flipped) {
            mFlipped = flipped;
            this.mFrontView.setVisibility(flipped ? View.GONE : View.VISIBLE);
            this.mBackView.setVisibility(flipped ? View.VISIBLE : View.GONE);
        }
    }
    

    就是这样!

    完成此设置后,您可以通过调用来翻转视图

    mFlipAnimator.start();
    

    并通过调用来反转翻转

    mFlipAnimator.reverse();
    

    如果要检查视图是否翻转,实现并调用该函数:

    private boolean isFlipped() {
        return mFlipAnimator.getAnimatedFraction() == 1;
    }
    

    您还可以通过实现此方法检查视图当前是否正在翻转:

    private boolean isFlipping() {
        final float currentValue = mFlipAnimator.getAnimatedFraction();
        return (currentValue < 1 && currentValue > 0);
    }
    

    你可以结合上面的函数来实现一个很好的函数来切换翻转,这取决于它是否被翻转:

    private void toggleFlip() {
        if(isFlipped()){
            mFlipAnimator.reverse();
        } else {
            mFlipAnimator.start();
        }
    }
    

    就是这样!简单易行。享受吧!

    【讨论】:

    • 我正在尝试将您的算法转换为 XML 补间动画。我不知道如何正确设置 pivotX 和 pivotY 属性:你知道吗?
    • @AntonioSesto 抱歉,我主要在没有 xml 的情况下制作动画,因为我发现代码中的动画更加通用。我认为在 xml 中设置枢轴会很困难,因为您不知道视图尺寸。也许您可以将其设置为百分比,您是否尝试将枢轴设置为 50%p 之类的值?
    • 这完美无瑕!!感谢您发布此答案!感谢帮助!来自我的 +1
    • 我花了几个小时才找到一个不涉及片段的答案,动画两个视图而不仅仅是一个,是 3d,并且实际上适用于正向和反向翻转。就是这样,谢谢!!
    • 真的太棒了,我在 kotlin 中使用相对布局中的旋转来实现,效果很好。谢谢
    【解决方案3】:

    我创建了一个简单的程序来创建视图翻转,例如:

    在 Activity 中你必须创建这个方法,用于在视图中添加翻转旋转。

    private void applyRotation(View view) 
    {
        final Flip3dAnimation rotation = new Flip3dAnimation(view);
        rotation.applyPropertiesInRotation();
        view.startAnimation(rotation);
    }
    

    为此,您必须复制用于提供翻转旋转的主类。

    import android.graphics.Camera;
    import android.graphics.Matrix;
    import android.util.Log;
    import android.view.View;
    import android.view.animation.AccelerateInterpolator;
    import android.view.animation.Animation;
    import android.view.animation.Transformation;
    
    public class Flip3dAnimation extends Animation {
        private final float mFromDegrees;
        private final float mToDegrees;
        private final float mCenterX;
        private final float mCenterY;
        private Camera mCamera;
    
        public Flip3dAnimation(View view) {
            mFromDegrees = 0;
            mToDegrees = 720;
            mCenterX = view.getWidth() / 2.0f;
            mCenterY = view.getHeight() / 2.0f;
        }
    
        @Override
        public void initialize(int width, int height, int parentWidth,
                int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
            mCamera = new Camera();
        }
    
        public void applyPropertiesInRotation()
        {
            this.setDuration(2000);
            this.setFillAfter(true);
            this.setInterpolator(new AccelerateInterpolator());
        }
    
        @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();
    
            Log.e("Degree",""+degrees) ;
            Log.e("centerX",""+centerX) ;
            Log.e("centerY",""+centerY) ;
    
            camera.rotateY(degrees);
    
            camera.getMatrix(matrix);
            camera.restore();
    
            matrix.preTranslate(-centerX, -centerY);
            matrix.postTranslate(centerX, centerY);
    
        }
    
    }
    

    【讨论】:

    • 这很好,但最好不要依赖自定义动画函数,而是使用 ObjectAnimators。原因是更好的支持和可逆性。
    • @Tushar Pandey :- 令人兴奋.. 多么好的答案.. grt 老兄
    【解决方案4】:

    本教程或 om252345 的链接不会产生可信的 3D 翻转。 y 轴上的简单旋转不是 iOS 中所做的。还需要缩放效果来创造良好的翻转感觉。为此,请查看this example。 还有视频here

    【讨论】:

    • 我意识到问题是关于如何使用 xml 在 android.com 示例中进行 y 轴旋转。但我想也许你也对此感兴趣。
    【解决方案5】:

    在不使用资源动画的情况下翻转图像的一种更好的解决方案如下:-

      ObjectAnimator animation = ObjectAnimator.ofFloat(YOUR_IMAGEVIEW, "rotationY", 0.0f, 360f);  // HERE 360 IS THE ANGLE OF ROTATE, YOU CAN USE 90, 180 IN PLACE OF IT,  ACCORDING TO YOURS REQUIREMENT 
    
      animation.setDuration(500); // HERE 500 IS THE DURATION OF THE ANIMATION, YOU CAN INCREASE OR DECREASE ACCORDING TO YOURS REQUIREMENT
      animation.setInterpolator(new AccelerateDecelerateInterpolator());
      animation.start();
    

    【讨论】:

      【解决方案6】:
      1. 最简单的方法是使用ViewPropertyAnimator

        mImageView.animate().rotationY(360f);
        

        使用流畅的界面,您可以构建更复杂、更精彩的动画。 例如。您只需调用 withLayer() 方法(API 16)即可启用硬件加速。更多here

      2. 如果您想了解如何制作 3d 动画,请关注 herehere

      3. 我实施自己的解决方案仅用于研究。它包括:取消、加速、支持 API >= 15 并且基于Property Animation。 整个动画包括4个部分,每边2个。 每个 objectAnimator 都有一个侦听器,它定义当前动画索引并在 onAnimationStart 中表示图像,在 onAnimationCancel 中表示当前播放时间值。 好像

        mQuarterAnim1.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                mQuarterCurrentAnimStartIndex = QUARTER_ANIM_INDEX_1;
                mImageView.setImageResource(mResIdFrontCard);
            }
        
            @Override
            public void onAnimationCancel(Animator animation) {
                mQuarterCurrentAnimPlayTime = ((ObjectAnimator) animation).getCurrentPlayTime();
            }
        });
        

        对于开始集合调用

        mAnimatorSet.play(mQuarterAnim1).before(mQuarterAnim2)
        

        如果取消了 AnimatorSet,我们可以根据当前索引动画和当前播放时间值计算 delta 并运行反向动画。

        long degreeDelta = mQuarterCurrentAnimPlayTime * QUARTER_ROTATE / QUARTER_ANIM_DURATION;
        
        if (mQuarterCurrentAnimStartIndex == QUARTER_ANIM_INDEX_1) {
            mQuarterAnim4.setFloatValues(degreeDelta, QUARTER_FROM_1);
            mQuarterAnim4.setDuration(mQuarterCurrentAnimPlayTime);
        
            mAnimatorSet.play(mQuarterAnim4);
        }
        

      完整代码sn-p你可以找到here

      【讨论】:

      • 很好的解释@yoAlex5 +1 :)
      【解决方案7】:

      只需将要为其设置动画的视图代替 viewToFlip。

      ObjectAnimator flip = ObjectAnimator.ofFloat(viewToFlip, "rotationY", 0f, 360f); // or rotationX
      flip.setDuration(2000); // 2 seconds
      flip.start();
      

      【讨论】:

      • 我正在将您的答案修改为质量较差的答案,您应该在代码中添加解释...
      【解决方案8】:

      添加到 A. Steenbergen 的出色答案。翻转相同视图时(例如更新TextView),我删除了构造函数中的View.Visibility 更改,以保持过渡更平滑。

      public FlipListener(final View front, final View back) {
          this.mFrontView = front;
          this.mBackView = back;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-06
        • 2011-03-22
        • 1970-01-01
        • 2017-05-23
        相关资源
        最近更新 更多