Android动画

作者: 感冒没吃药 | 来源:发表于2017-07-07 17:55 被阅读66次

    Drawable Animation

    帧动画,多张图片循环播放,实现动画效果。

    以Xml定义一组帧动画

    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="true">
        <item
            android:drawable="@drawable/a1"
            android:duration="200" />
        <item
            android:drawable="@drawable/a2"
            android:duration="200" />
        <item
            android:drawable="@drawable/a3"
            android:duration="200" />
        <item
            android:drawable="@drawable/a4"
            android:duration="200" />
        <item
            android:drawable="@drawable/a5"
            android:duration="200" />
    </animation-list>
    

    oneshot表示动画是否只执行一次。

    每一帧的动画可以设置图层,让同一帧能有几个图。

        <item android:duration="100">  
            <layer-list>  
                <item android:drawable="@drawable/login_loading_1" />  
                <item android:drawable="@drawable/login_loading_2" />  
            </layer-list>  
        </item>  
    

    帧动画图片多,可能会有内存溢出的问题、

    View Animation

    视图动画,又叫补间动画,有旋转,透明度,大小,位移四种动画效果,特点是实现简单,但是动画并不改变实际view的属性

    用代码实现动画

    TranslateAnimation 平移动画

     TranslateAnimation ta = new TranslateAnimation(0,400,0,0);//左平移400个单位
     ta.setDuration(2000);
     view.startAnimation(ta);
    

    AlphaAnimation 透明度动画

      AlphaAnimation aa = new AlphaAnimation(1.0f,0.5f);//从不透明到半透明
      aa.setDuration(2000);
      view.startAnimation(aa)
    

    RotateAnimation 旋转动画

      RotateAnimation ra = new RotateAnimation(0,180);
      ra.setDuration(2000);
      view.startAnimation(ra);
    

    ScaleAnimation 缩放动画

     ScaleAnimation sa = new ScaleAnimation(0,5,0,5);
     sa.setDuration(2000);
     view.startAnimation(ra);
    

    其中除AlphaAnimation之外其余三种动画的参考坐标系有三种。

    • 默认是view的左上角。
    • 以及view自身:Animation.RELATIVE_TO_SELF
    • 还有view的父控件:Animation.RELATIVE_TO_PARENT

    这里说的参考系,可以理解成一个关键点的确定

    这是一个300*300px的ViewGroup,背景图是个圆,小红点位于ViewGroup的左上角
    以TranslateAnimation来看这三种参考坐标系

    TranslateAnimation ta1 = new TranslateAnimation(0,150,0,0);
    //TranslateAnimation ta2 = new TranslateAnimation(Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,10f,Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0);
    //TranslateAnimation ta3 = new TranslateAnimation(Animation.RELATIVE_TO_PARENT,0,Animation.RELATIVE_TO_PARENT,1f,Animation.RELATIVE_TO_PARENT,0,Animation.RELATIVE_TO_PARENT,0);
    ta1.setDuration(2000);
    image.startAnimation(ta1);
    


    三种设置分别对应三个gif图,第一个是以左上角为参考点,右平移150个单位(px)

    第二个是以自身为参考,右平移自身10倍的距离。

    第三个是以父控件为参考,右平移父控件一倍宽的距离。

    ScaleAnimation有个比较有意思的地方。如果参考点不在原先的view上,缩放之后的view会带移动的效果。

     ScaleAnimation sa1 = new ScaleAnimation(1,5,1,5,-10,0);
     ScaleAnimation sa = new ScaleAnimation(1,5,1,5,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
    

    比如说sa1这个ScaleAnimation,参考点在他的左侧-10px,0px的地方
    他放大五倍的效果是这样的

    由于参考点在圆的左边,所以圆是向右边移动的。实际上这个放大效果是把圆和他的参考点看成了一个整体,参考点固定不动,放大五倍的过程中,参考点和圆的距离10px也放大了五倍。

    让几个动画一起作用可以使用AnimationSet

    AnimationSet as = new AnimationSet(true);//boolean 是否共享插值器
    ScaleAnimation sa1 = new ScaleAnimation(1,5,1,5,-10,0);
    ScaleAnimation sa = new ScaleAnimation(1,5,1,5,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
    RotateAnimation ra = new RotateAnimation(0, 360f, Animation.RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 0.5f);
    as.setInterpolator(new AccelerateDecelerateInterpolator());
    as.addAnimation(sa1);
    as.addAnimation(ra);
    as.setDuration(2000);
    image.startAnimation(as);
    

    相比在代码里设置动画,一般还是用Xml来配置
    在res目录下新建文件夹anim用来存放动画文件

    如下代码

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
    
        <scale
            android:duration="1000"
            android:fillAfter="true"
            android:fromXScale="1"
            android:fromYScale="1"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toXScale="5"
            android:toYScale="5" />
    
        <set android:startOffset="1000">
            <translate
                android:duration="2000"
                android:fromXDelta="0"
                android:fromYDelta="0"
                android:toXDelta="200"
                android:toYDelta="0"
                />
            <alpha
                android:duration="2000"
                android:fromAlpha="1"
                android:toAlpha="0"
                />
        </set>
    </set>
    

    定义了一个一秒内放大五倍,接着一边平移一边消失的动画
    值得注意的是pivotX和pivotY参考点的确定,以view的左上角为0,0点,用绝对数值确定,比如pivotX="-10",pivotY="0",表示左上角往左10px的点,pivotX="50%"表示相对于自身的百分之50,pivotX="50%p"表示相对于父控件的百分之50.对应代码设置的三种坐标确定

    加载一个xml的Animation

    Animation animation =  AnimationUtils.loadAnimation(MainActivity.this,R.anim.animation);
    img.startAnimation(animation);
    

    Property Animation

    属性动画,通过改变View的属性,来达到动画的效果。
    因为改变的是属性值,所以动画会改变View的位置,大小等。
    一般要求改变的属性值有 get/set 方法

    属性动画有两个动画执行类分别是ObjectAnimator和ValueAnimator

    ObjectAnimator是ValueAnimator的子类,具有比ValueAnimator更强的封装性,使用代码更简洁,相反的,封装性不强的ValueAnimator则显得更加灵活,容易实现复杂的效果

    ObjectAnimator

    修改单个属性的动画效果

     ObjectAnimator.ofFloat(img,"rotation",0.0F,180F).setDuration(500).start();
    

    直接调用ObjectAnimator的ofFloat,ofInt,ofObject方法,第一个参数是作用的view,第二个是操作的属性,第三个是一个不定参,只填一个表示结束的属性值,填两个分别表示开头和结尾的属性值。

    多个属性值改变的动画效果,(同时改变)可以用PropertyValuesHolder

        PropertyValuesHolder pvha = PropertyValuesHolder.ofFloat("alpha", 1f, 0, 1f);
        PropertyValuesHolder pvhsx = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
        PropertyValuesHolder pvhsy = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
        ObjectAnimator.ofPropertyValuesHolder(view, pvha, pvhsx, pvhsy).setDuration(2000).start();
    

    ValueAnimator

    实际上,ValueAnimator可以看成是提供一个区间的计算过程。
    而实际的动画效果,需要我们在回调中自己去设置。
    例如:

                ValueAnimator valueAnimator = ValueAnimator.ofFloat(200.0F);
                valueAnimator.setTarget(img);
                valueAnimator.setDuration(2000).start();
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                        img.setTranslationY((Float) valueAnimator.getAnimatedValue());
                    }
                });
    

    因为ofFloat只传了一个参,所以200是结束值,区间是0-200;
    2000ms时间内在该区间内不断的递增,AnimatorUpdateListener里通过valueAnimator.getAnimatedValue()就能拿到某时刻的值,再根据需要进行设置,这里是平移200个px

    TypeEvaluator

    上面说道ValueAnimator可看成是提供一个区间的计算过程。实际上,这个计算的操作,是由TypeEvaluator来进行的。

    TypeEvaluator是一个接口,我们可以实现这个接口来实现自己的需求,也可以用Android提供的几个Evaluator

    比如:

                ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointFEvaluator(),new PointF(0,0),new PointF(100,100));
                valueAnimator.setDuration(2000).start();
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                        PointF pf = (PointF) valueAnimator.getAnimatedValue();
                        Log.e("walker","x值 : " + pf.x);
                        Log.e("walker","y值 : " + pf.y);
                    }
                });
    

    PointFEvaluator 是 自带的一个Evaluator,上面代码是(0,0)点到
    (100,100)的计算过程,过程中不断回调AnimatorUpdateListener
    因为我们没有为任何view设置动画,所以不会有什么动画效果,但是Log里可以看到2s间点的移动状态。毫无疑问,这是一条直线的运动轨迹

    自定义TypeEvaluator模拟抛物线效果

                ValueAnimator valueAnimator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() {
    
                    @Override
                    public PointF evaluate(float v, PointF o, PointF t1) {
                        
                        PointF pf = new PointF();
                        pf.x = 200 * v * 2;
                        pf.y = 0.5f * 200 * (v * 2) * (v * 2);
                        return pf;
                    }
                },new PointF(0,0));
    
                valueAnimator.setDuration(2000).start();
                valueAnimator.setInterpolator(new LinearInterpolator());
    
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
    
                        PointF point = (PointF) valueAnimator.getAnimatedValue();
                        ball.setX(point.x);
                        ball.setY(point.y);
                    }
                })
    

    关于动画状态的监听
    一个有四个状态,分别为开始,结束,取消,重复

                valueAnimator.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animator) {
                        
                    }
    
                    @Override
                    public void onAnimationEnd(Animator animator) {
    
                    }
    
                    @Override
                    public void onAnimationCancel(Animator animator) {
    
                    }
    
                    @Override
                    public void onAnimationRepeat(Animator animator) {
    
                    }
                })
    

    也可以用AnimatorListenerAdapter选择自己需要的监听
    比方说只需要动画结束的监听

                valueAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
    
                    }
                })
    

    AnimatorSet设置多个动画的执行

                ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img,"rotation",0.0F,360F);
    
                ValueAnimator valueAnimator = ValueAnimator.ofFloat(400.0F);
                valueAnimator.setTarget(img);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                        img.setTranslationY((Float) valueAnimator.getAnimatedValue());
                    }
                });
                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.setDuration(2000);
                animatorSet.playTogether(objectAnimator,valueAnimator);//一起执行
    //          animatorSet.playSequentially(objectAnimator,valueAnimator);//顺序执行
    //          animatorSet.play(objectAnimator).with(valueAnimator);//链式排列
                animatorSet.start();
    

    相关文章

      网友评论

        本文标题:Android动画

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