Android中实现Card Flip (卡片翻转)动画效果的探讨

来源:互联网 发布:程序员考试科目 编辑:程序博客网 时间:2024/04/28 21:29

在Google的官方文档中,我们可以看到在Android4.0 之后,Google提供了ObjectAnimator类来简单实现卡片翻转的动画效果:http://developer.android.com/training/animation/cardflip.html;如果要兼容4.0以下的Android API去实现卡片翻转效果,主要有两种实现方式:

/** * Created by keith on 12/12/2014. */@Deprecatedpublic class FlipAnimation extends Animation{            private Camera camera;            private View fromView;            private View toView;            private float centerX;            private float centerY;            private boolean forward = true;            public FlipAnimation(View fromView, View toView){                this.fromView = fromView;                this.toView = toView;                setDuration(500);                setFillAfter(false);                setInterpolator(new LinearInterpolator());            }            public void reverse(){                forward = false;        View switchView = toView;        toView = fromView;        fromView = switchView;    }    @Override    public void initialize(int width, int height, int parentWidth, int parentHeight){        super.initialize(width, height, parentWidth, parentHeight);        centerX = width / 2;        centerY = height /2;        camera = new Camera();    }    @Override    protected void applyTransformation(float interpolatedTime, Transformation t) {        final double radians = Math.PI * interpolatedTime;        float degrees = (float) (180.0 * radians / Math.PI);        if(interpolatedTime <= 0.05f){            fromView.setScaleX(1 - interpolatedTime);            fromView.setScaleY(1 - interpolatedTime);            toView.setScaleX(1 - interpolatedTime);            toView.setScaleY(1 - interpolatedTime);        }        if(interpolatedTime >= 0.5f){            degrees -= 180.f;            toView.bringToFront();            toView.getParent().requestLayout();            ((View)toView.getParent()).invalidate();            fromView.setVisibility(View.GONE);            toView.setVisibility(View.VISIBLE);        }        if (interpolatedTime >= 0.95f) {            fromView.setScaleX(interpolatedTime);            fromView.setScaleY(interpolatedTime);            toView.setScaleX(interpolatedTime);            toView.setScaleY(interpolatedTime);        }        final Matrix matrix = t.getMatrix();        camera.save();        camera.translate(0, 0, Math.abs(degrees)*2);        camera.getMatrix(matrix);        camera.rotateY(degrees);        camera.getMatrix(matrix);        camera.restore();        matrix.preTranslate(-centerX, -centerY);        matrix.postTranslate(centerX, centerY);    }}

大致思路便是在一个RootView中定义两个View,分别是卡片的正面和背面。布局大致如下

<RelativeLayout        android:id="@+id/root_holder"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_below="@+id/notice_holder"        android:layout_above="@+id/bottom_bar">        <FrameLayout            android:id="@+id/content_holder"            android:layout_width="match_parent"            android:layout_height="match_parent"/>        <FrameLayout            android:id="@+id/list_content_holder"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:visibility="gone"            />    </RelativeLayout>
最后将翻转动作抽象成一个方法,即可调用

private void flipCard(View view){        View rootLayout = view.findViewById(R.id.root_holder);        View cardFace = view.findViewById(R.id.content_holder);        View cardBack = view.findViewById(R.id.list_content_holder);        FlipAnimation flipAnimation = new FlipAnimation(cardFace, cardBack);        if(cardFace.getVisibility() == View.GONE){            flipAnimation.reverse();        }        rootLayout.startAnimation(flipAnimation);    }
方法二:

使用NineOld包实现具有兼容性的卡片翻转动画,由于使用了第三方的包所以相比之下此方法比方法一来的更简单,NineOld的官方地址点这,不了解的同学可以移步先去了解下,当然了,下载地址也在链接中。

首先是动画文件的实现,由于使用了NineOld包,xml的实现方式基本和从Google官网下的差不多

card_flip_left_in:

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?><!--Do not use it, not smooth --><set xmlns:android="http://schemas.android.com/apk/res/android">    <objectAnimator        android:valueFrom="1.0"        android:valueTo="0.0"        android:propertyName="alpha"        android:duration="0" />        <objectAnimator        android:valueFrom="-180"        android:valueTo="0"        android:propertyName="rotationY"        android:interpolator="@android:interpolator/accelerate_decelerate"        android:duration="500" />        <objectAnimator        android:valueFrom="0.0"        android:valueTo="1.0"        android:propertyName="alpha"        android:startOffset="250"        android:duration="1" /></set></span>
card_flip_left_out:

<?xml version="1.0" encoding="utf-8"?>    <!--Do not use it, not smooth --><set xmlns:android="http://schemas.android.com/apk/res/android">    <objectAnimator        android:valueFrom="0"        android:valueTo="180"        android:propertyName="rotationY"        android:interpolator="@android:interpolator/accelerate_decelerate"        android:duration="500" />    <objectAnimator        android:valueFrom="1.0"        android:valueTo="0.0"        android:propertyName="alpha"        android:startOffset="250"        android:duration="1" /></set>
在代码中调用这两个动画文件便能实现卡片翻转式的动画效果

View cardFace = getView().findViewById(R.id.content_holder);        View cardBack = getView().findViewById(R.id.list_content_holder);        if(animation) {            cardBack.setVisibility(View.VISIBLE);            cardFace.setVisibility(View.VISIBLE);            Animator animatorIn = AnimatorInflater.loadAnimator(getActivity(), R.anim.card_flip_left_in);            Animator animatorOut = AnimatorInflater.loadAnimator(getActivity(), R.anim.card_flip_left_out);            if (flag) {                animatorIn.setTarget(cardBack);                animatorOut.setTarget(cardFace);                flag = false;            }else{                animatorIn.setTarget(cardFace);                animatorOut.setTarget(cardBack);                flag = true;            }            animatorOut.start();            animatorIn.start();        }
需要注意的是,这里的Animator和AnimatorInflater都是NineOld类中的动画类。

说到这里,心细的同学有可能发现在这两种方式中,笔者分别使用了“@Deprecated”和“Do not ues it”,这是为什么呢?笔者发现如果View中的内容比较单一,占用内存资源较少,大可放心使用此翻转动画;但是如果View中的内容较多,就需要权衡一下,笔者在开发过程中需要实现此翻转动画,两个翻转的View中,一个是每个Cell都有图片的ListView,一个是拥有数十数百个Marker的Map,在翻转的时候出现了极其严重的卡顿(和IOS相比),最后不得不放弃了实现这个功能。欢迎大家一起探讨和学习,谢谢!


参考文献

https://github.com/carlol/AndroidCardFlip/blob/master/src/io/carlol/test/cardflip/ui/CardFlip.java





0 0