美文网首页ITBOXAndroid进阶android开发文集
利用Camera和Matrix实现有趣的卡片效果

利用Camera和Matrix实现有趣的卡片效果

作者: zhangke3016 | 来源:发表于2016-08-07 16:43 被阅读2460次
    FlipCards

    这篇文章主要讲解一个翻转切换内容的卡片效果,主要利用Camera和Matrix来实现,主要是为了加深对Camera和Matrix的理解,如果对Camera和Matrix不清楚地童鞋可以看我的上篇文章:Android中利用Camera与Matrix实现3D效果详解
    好了,我们先看下效果吧 (效果的灵感来自:Dribbble):

    FlipCards

    项目github地址
    欢迎star、fork。

    实现思路:
    一、主要应用Animation进行实现,创建一个继承自Animation的自定义动画,在applyTransformation()方法中进行逻辑判断。
    二 、考虑到旋转180度后控件文字会是倒过来显示的,并且旋转360度后虽然文字正常显示了但效果不好,所以在applyTransformation方法中对角度进行动态的修改。
    三、为了使外部可以在控件翻转过程中修改内容,在自定义的Animation中添加了监听接口,用于监听内容变化的时机。
    四、外部控件调用startAnimation()方法即可使用。

    具体实现

    当然我们也可以用自定义控件的方式实现,但考虑到实现的复杂性和使用性,我没有选择。
    知道了实现思路,那么我们开始着手开始吧:
    第一步:自定义Animation,覆写initialize和applyTransformation方法

    public class FlipCardAnimation extends Animation{
     @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) {
        
        }
    }
    

    在initialize方法中初始化Camera对象。

    第二步:
    在applyTransformation方法中实现逻辑:

      @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 (degrees>90 || degrees<-90){
                if (!isContentChange){
                    if(listener!=null){
                        listener.contentChange();
                    }
                    isContentChange = true;
                }
    
                if (degrees>0) {
                    degrees = 270 + degrees - 90;
                }else if (degrees<0){
                    degrees = -270+(degrees+90);
                }
            }
    
            camera.rotateX(degrees);
    
            camera.getMatrix(matrix);
    
            camera.restore();
    
            matrix.preTranslate(-centerX, -centerY);
    
            matrix.postTranslate(centerX, centerY);
        }
    

    在这里需要注意的地方是,当卡片顺时针或者逆时针旋转的时候对角度进行判断,当旋转大于90度或者小于-90度时,将之后的角度调整为270度到360度或者-270度到-360度之间,以此来实现卡片内容正常显示,如果不做处理,我们翻转过后的文字是倒过来显示的。

    第三步:设置内容变化监听,方便外部对卡片内容做修改

     private OnContentChangeListener listener;
    
        public void setOnContentChangeListener(OnContentChangeListener listener) {
            this.listener = listener;
        }
    
        public interface OnContentChangeListener{
            void contentChange();
        }
    

    为了确保外部每次开启动画内容都会变动,务必在开始之前调用方法setCanContentChange():

    animation.setCanContentChange();
    

    如果设置循环动画,则要在监听中设置setCanContentChange()方法:

    animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                    }
                    @Override
                    public void onAnimationEnd(Animation animation) {
                    }
                    @Override
                    public void onAnimationRepeat(Animation animation) {
                        ((FlipCardAnimation)animation).setCanContentChange();
                    }
                });
    

    第四步:为控件设置并开启动画

    这一步就比较简单了,都是常用的对Animation的设置:

    animation = new FlipCardAnimation(0, degree, width, height);
                animation.setInterpolator(new AnticipateOvershootInterpolator());
                animation.setDuration(3000);
                animation.setFillAfter(false);
                animation.setRepeatCount(-1);//设置无限循环
                animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                    }
                    @Override
                    public void onAnimationEnd(Animation animation) {
                    }
                    @Override
                    public void onAnimationRepeat(Animation animation) {
                        ((FlipCardAnimation)animation).setCanContentChange();//如果设置循环,务必在这里添加这行代码
                    }
                });
                animation.setOnContentChangeListener(new FlipCardAnimation.OnContentChangeListener() {
                    @Override
                    public void contentChange() {
                        if (iv_pro == null) {
                            return;
                        }
                        iv_pro.setBackgroundResource(DRAWABLE[num]);
                        tv_item.setText("¥" + new Random().nextInt(500));
                        tv_price_item.setText("Discount");
                    }
                });
                llyt_item.startAnimation(animation);
    

    到此,其实我们的翻转卡片效果就已经差不多完成了。在设置Animation的时候有setInterpolator()这个方法,interpolator插补器可以用来设置动画运动时的速率,插补器的原理就是通过改变实际执行动画的时间点,提前/延迟执行默认的时间点来达到加速/减速的效果。这里再多说下Interpolator的几个子类,也是为了自己以后记忆和查找,大家可以设置不同的插补器看下效果。

    AccelerateDecelerateInterpolator 在动画开始与介绍的地方速率改变比较慢,在中间的时侯加速
    AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速
    CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
    DecelerateInterpolator 动画开始的地方快然后慢
    LinearInterpolator 在动画的以均匀的速率改变
    AnticipateInterpolator 向前插补器,开始的时候向后然后向前甩
    AnticipateOvershootInterpolator 向前向后插补器,开始的时候向后然后向前甩,结束时向前甩一定值后再返回最后的值
    OvershootInterpolator 超出插补器,结束时向前甩一定值后再回到原来位置
    BounceInterpolator 动画结束的时候弹起

    项目github地址:https://github.com/zhangke3016/FlipCards】如果觉得有趣欢迎star、fork。

    相关文章

      网友评论

      本文标题:利用Camera和Matrix实现有趣的卡片效果

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