Android里的动画(补间动画,帧动画,属性动画)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_37667770/article/details/80007225

Android动画的学习

常见的动画分为:

-补间动画
-帧动画
- 属性动画


学完这个分享自己项目一个简单的动画:

这里写图片描述

转场动画:这个是谷歌提供的样式!下面自己模仿了一下。
这里写图片描述

模仿谷歌设计来自己做了一个。
这里写图片描述

一补间动画:

对于学过flash动画的人来说补间动画很好理解的,因为动画开始和结尾的中间过程都是假象,是渲染出来的表象,只是显示的位置变动,View的实际位置未改变,表现为View移动到其他地方,点击事件仍在原处才能响应。

补间动画由Animation类来实现具体效果,包括平移(TranslateAnimation)、缩放(ScaleAnimation)、旋转(RotateAnimation)、透明度(AlphaAnimation)四个子类。

实现:

补间动画在android里面支持xml来设置或者java代码设置。
常见的布局动画类如下:

TranslateAnimation

translate属性 TranslateAnimation 含义
android:fromXDelta TranslateAnimation translateAnimation=TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta); 平移起点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点50%表示以当前View的左上角加上当前View宽高的50%做为初始点50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)
android:fromYDelta 同上 同理fromXDelta
android:toXDelta 同上 平移终点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点50%表示以当前View的左上角加上当前View宽高的50%做为初始点50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)
android:toYDelta 同上 同上
android:fillAfter translateAnimation.setFillAfter(true); 动画显示结束保持最后一帧
android:duration translateAnimation.setDuration(3000); 动画执行的时间
android:repeatCount translateAnimation.setRepeatCount(TranslateAnimation.INFINITE); 动画执行的次数可以是整数或者infinite为无限循环执行动画

使用如下:

translate.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toXDelta="100%"
    android:toYDelta="-100%"
    android:fillAfter="true"
    android:duration="1000"
    >

</translate>

AlphaAnimation

Alpha属性 AlphaAnimation 含义
android:fromAlpha AlphaAnimation alphaAnimation=new AlphaAnimation(float fromAlpha, float toAlpha); 是View视图起始透明度,透明度是0-1
android:toAlpha 同上 结束时的透明度
android:fillAfter alphaAnimation.setFillAfter(true); 动画显示结束保持最后一帧
android:duration alphaAnimation.setDuration(3000); 动画执行的时间
android:repeatCount alphaAnimation.setRepeatCount(TranslateAnimation.INFINITE); 动画执行的次数可以是整数或者infinite为无限循环执行动画

使用如下:

alpha.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="1"
    android:toAlpha="0.5"
    android:fillAfter="true"
    android:duration="3000"
    >

</alpha>

RotateAnimation

RotateAnimation 属性 RotateAnimation 含义
android:fromDegrees RotateAnimation rotateAnimation=RotateAnimation(float fromDegrees, float toDegrees); 是View视图起始角度
android:toDegrees 同上 结束时的角度
android:fillAfter rotateAnimation.setFillAfter(true); 动画显示结束保持最后一帧
android:duration rotateAnimation.setDuration(3000); 动画执行的时间
android:repeatCount rotateAnimation.setRepeatCount(TranslateAnimation.INFINITE); 动画执行的次数可以是整数或者infinite为无限循环执行动画

使用如下:

rotate.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="90"
    android:fillAfter="true"
    android:duration="3000"
    >

</rotate>

ScaleAnimation

ScaleAnimation属性 ScaleAnimation 含义
android:fromXScale ScaleAnimation scaleAnimation=ScaleAnimation(float fromX, float toX, float fromY, float toY) 这个相信能看懂。
android:toXScale 同上 结束时的位置
android:fillAfter scaleAnimation.setFillAfter(true); 动画显示结束保持最后一帧
android:duration scaleAnimation.setDuration(3000); 动画执行的时间
android:repeatCount scaleAnimation.setRepeatCount(TranslateAnimation.INFINITE); 动画执行的次数可以是整数或者infinite为无限循环执行动画

使用如下:

scale .xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXScale="0.5"
    android:toXScale="1"
    android:fromYScale="0.5"
    android:toYScale="1"
    android:fillAfter="true"
    android:duration="3000"
    >

</scale>

AnimationSet

当然了有动画集合这个类了。使用也是很简单的:

set.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fillAfter="true"
    android:shareInterpolator="true"
    android:repeatMode="reverse"
    >
    <scale
        android:duration="1000"
        android:fillAfter="true"
        android:fromXScale="0.5"
        android:fromYScale="0.5"
        android:toXScale="1"
        android:toYScale="1"
        android:repeatCount="infinite"/><!--次数 ,infinite这个为无线循环播放哦-->
    <alpha
        android:duration="2000"
        android:fillAfter="true"
        android:fromAlpha="0.7"
        android:toAlpha="1"/>
    <rotate
        android:fromDegrees="0"
        android:toDegrees="90"
        android:fillAfter="true"
        android:duration="1000"
        />
    <translate
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="100%"
        android:toYDelta="-100%"
        android:fillAfter="true"
        android:duration="2000"
        />
</set>
button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /*
                //位移动画
                Animation animation= AnimationUtils.loadAnimation(MainActivity.this,R.anim.translate);
                button.setAnimation(animation);
                TranslateAnimation translateAnimation=new TranslateAnimation(0,200,0,200);
                AlphaAnimation translateAnimation=new AlphaAnimation(0.5f,1f);
                translateAnimation.setDuration(3000);
                translateAnimation.setRepeatMode(TranslateAnimation.INFINITE);
                translateAnimation.setRepeatCount(TranslateAnimation.INFINITE);
                translateAnimation.setFillAfter(true);
                */

               /*
                //渐变动画
                AlphaAnimation alphaAnimation=new AlphaAnimation(0.5f,1f);
                alphaAnimation.setDuration(3000);
                alphaAnimation.setRepeatMode(TranslateAnimation.INFINITE);
                alphaAnimation.setRepeatCount(TranslateAnimation.INFINITE);
                alphaAnimation.setFillAfter(true);
                button.startAnimation(alphaAnimation);*/

               /*
               * //旋转动画
               * public RotateAnimation(float fromDegrees, float toDegrees) {
               *
                RotateAnimation rotateAnimation=new RotateAnimation(0,90);
                rotateAnimation.setDuration(3000);
                rotateAnimation.setRepeatMode(TranslateAnimation.INFINITE);
                rotateAnimation.setRepeatCount(TranslateAnimation.INFINITE);
                rotateAnimation.setFillAfter(true);
                button.startAnimation(rotateAnimation);*/

               /*
               * 缩放动画
               *
               *
                ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 0.7f, 0.5f, 0.7f);
                scaleAnimation.setDuration(3000);
                scaleAnimation.setRepeatMode(TranslateAnimation.INFINITE);
                scaleAnimation.setRepeatCount(TranslateAnimation.INFINITE);
                scaleAnimation.setFillAfter(true);
                button.startAnimation(scaleAnimation); */
                AlphaAnimation alphaAnimation=new AlphaAnimation(0.5f,1f);
                alphaAnimation.setDuration(3000);
                alphaAnimation.setRepeatMode(TranslateAnimation.INFINITE);
                alphaAnimation.setRepeatCount(TranslateAnimation.INFINITE);
                alphaAnimation.setFillAfter(true);
                button.startAnimation(alphaAnimation);

                RotateAnimation rotateAnimation=new RotateAnimation(0,90);
                rotateAnimation.setDuration(3000);
                rotateAnimation.setRepeatMode(TranslateAnimation.INFINITE);
                rotateAnimation.setRepeatCount(TranslateAnimation.INFINITE);
                rotateAnimation.setFillAfter(true);
                button.startAnimation(rotateAnimation);

                ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 0.7f, 0.5f, 0.7f);
                scaleAnimation.setDuration(3000);
                scaleAnimation.setRepeatMode(TranslateAnimation.INFINITE);
                scaleAnimation.setRepeatCount(TranslateAnimation.INFINITE);
                scaleAnimation.setFillAfter(true);
                button.startAnimation(scaleAnimation);

                //动画集合
                AnimationSet animationSet=new AnimationSet(true);
                animationSet.addAnimation(alphaAnimation);
                animationSet.addAnimation(rotateAnimation);
                animationSet.addAnimation(scaleAnimation);


                animationSet.setDuration(2000);
                animationSet.setRepeatMode(AnimationSet.INFINITE);
                animationSet.setRepeatCount(AnimationSet.INFINITE);

                button.setAnimation(animationSet);

            }
        });

效果图如下:

1.给简单的view控件设置动画:

这里写图片描述

2.给Activity设置转场动画:

缩放,淡入淡出,滑进滑出….很多由你来设置:这里为了演示效果设置时间很长。用时候可以设置短。
如下图:第一个页面跳转第二个Activity页面动画效果:
这里写图片描述

淡入淡出的:
这里写图片描述

这里在demon里面activity跳转动画都写了好多开参考。
这里写图片描述

可能很多人不明白100%p和100%这样的问题。明确知道左下角为坐标原点。看看别人的博客就懂了

这里写图片描述

如上图:Activity A从-100%p滑到0即从位置一滑到位置二。很简单的理解。看图就知道了。

二,属性动画:

由于3.0之前的View动画太过单一,不能够满足开发和用户,所以谷歌在3.0之后提出了属性动画
,属性动画是从3.0及以后出现的(如果要兼容低版本,可以使用一个民间版第三方的一个jar NineOldAndroid.jar,用法跟系统的用法差不多)。不断地控制控件的属性变化达到动画的效果,一般我们是一些组合的属性动画达到复杂的效果。

使用:

使用1:

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "translationX", 0f, 300f);
        objectAnimator.setDuration(4000);
        objectAnimator.setRepeatCount(ObjectAnimator.INFINITE);
        objectAnimator.start();


        ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view, "translationY", 0f, 300f);
        objectAnimator1.setDuration(7000);
        objectAnimator1.setRepeatCount(ObjectAnimator.INFINITE);
        objectAnimator1.start();


        ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view, "scaleX", 0.2f, 1f);
        objectAnimator2.setDuration(6000);
        objectAnimator2.setRepeatCount(ObjectAnimator.INFINITE);
        objectAnimator2.start();

        ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(view, "scaleY", 0.2f, 1f);
        objectAnimator3.setDuration(6000);
        objectAnimator3.setRepeatCount(ObjectAnimator.INFINITE);
        objectAnimator3.start();

        ObjectAnimator objectAnimator4=ObjectAnimator.ofFloat(view,"alpha",0.5f,1f);
        objectAnimator4.setDuration(6000);
        objectAnimator4.setRepeatCount(ObjectAnimator.INFINITE);
        objectAnimator4.start();

使用2:

ObjectAnimator animator = ObjectAnimator.ofFloat(button, "haha", 0f, 100f);//没有这个属性的时候,就是valueanimator
        animator.setDuration(300);
        //设置动画监听
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //动画在执行的过程当中,不断地调用此方法
//              animation.getAnimatedFraction()//百分比
                //得到duration时间内 values当中的某一个中间值。0f~100f
                float value = (float) animation.getAnimatedValue();//
                button.setScaleX(0.5f+value/200);//0.5~1
                button.setScaleY(0.5f+value/200);//0.5~1
            }
        });
        animator.start();

使用3:

  ValueAnimator valueAnimator=ValueAnimator.ofFloat(0f,200f);
        valueAnimator.setDuration(200);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //              //动画在执行的过程当中,不断地调用此方法
////            animation.getAnimatedFraction()//百分比
//          //得到duration时间内 values当中的某一个中间值。0f~100f
                float value = (float) animation.getAnimatedValue();//
                button.setScaleX(0.5f + value / 200);//0.5~1
                button.setScaleY(0.5f + value / 200);//0.5~1
            }
        });

        valueAnimator.start();

使用4:

//3)方法3
        //float... values:代表关键帧的值
        PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 1f,0.7f,1f);
        PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1f,0.7f,1f);
        PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1f,0.7f,1f);
//      PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("translationX", 0f,300f);

        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(button, holder1,holder2,holder3);
        animator.setDuration(1000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // TODO Auto-generated method stub
                float animatedValue = (float) animation.getAnimatedValue();
                float animatedFraction = animation.getAnimatedFraction();
                long playTime = animation.getCurrentPlayTime();

                System.out.println("animatedValue:"+animatedValue+",  playTime:"+playTime);
            }
        });
        animator.start();

动画集合:

    //4)方法4:-----------------动画集合--------------------
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(button,"alpha", 1f,0.7f,1f);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(button,"scaleX", 1f,0.7f,1f);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(button,"scaleY", 1f,0.7f,1f);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setDuration(500);
//      animatorSet.play(anim);//执行当个动画
//      animatorSet.playTogether(animator1,animator2,animator3);//同时执行
        animatorSet.playSequentially(animator1,animator2,animator3);//依次执行动画
        animatorSet.start();

实现一个抛物线:

首先抛物线方程:水平方向:x:匀速运动:
竖着方向:y=1/2*g*t*t


        ValueAnimator valueAnimator=new ValueAnimator();
        valueAnimator.setDuration(4000);
        valueAnimator.setObjectValues(new PointF(0,0));//起点坐标
        //估值器:====定义计算规则
        valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
            @Override
            public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
                //拿到每一个时间点的坐标:
                //x
                PointF pointF=new PointF();
                //x=vt
                pointF.x=100f*fraction*4;//初始速度*执行的百分比
                pointF.y=0.5f*100f*(fraction*4)*(fraction*4);//为了30明显我把g设置成


                return pointF;
            }

        });

        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //得到此事件点的坐标
                PointF pointF= (PointF) animation.getAnimatedValue();


                button.setX(pointF.x);
                button.setY(pointF.y);
            }
        });

        valueAnimator.start();

这里写图片描述

案例代码:

 //2017年11月10日:实现点击旋转动画这个有点小复杂
        ibTop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isWmflag) {//如果是女生
                    if (count % 2 == 0 && endOther) {//如果在人体前面进行点击旋转进行旋转动画且切换图片哦
                        endOther = false;
                        ObjectAnimator oa = ObjectAnimator.ofFloat(home_man_iv, "rotationY",
                                new float[]{0f, 60f, 120f, 180f});
                        oa.setDuration(1000);
                        oa.setRepeatCount(0);
                        oa.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                //这个值是获取对应的什么时间进行切换图片。首先设置了0f,60f,120f,180f这四个插入值作为旋转角度,当90度时候我们来切换背景图片达到旋转切换。
                                float playTime = (float) animation.getAnimatedValue();
                                if (playTime >= 90) {

                                    home_man_iv.setBackgroundResource(R.drawable.female_b);
                                }
                                //当180度时候我们进行标记。这个旋转结束了。可以点击进行下一个动画了。endOther作为标记。
                                if (playTime == 180f) {
                                    count++;
                                    endOther = true;
                                }
                            }
                        });
                        oa.start();
                    } else if (endOther) {//如果是女生
                        endOther = false;
                        ObjectAnimator oa = ObjectAnimator.ofFloat(home_man_iv, "rotationY",
                                new float[]{0f, 60f, 120f, 180f});
                        oa.setDuration(1000);
                        oa.setRepeatCount(0);
                        oa.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                float playTime = (float) animation.getAnimatedValue();
                                if (playTime >= 90) {
                                    home_man_iv.setBackgroundResource(R.drawable.female_f);
                                }
                                if (playTime == 180f) {
                                    count++;
                                    endOther = true;
                                }
                            }
                        });
                        oa.start();
                    }

                } else {
                    if (count % 2 == 0 && endOther) {
                        endOther = false;
                        ObjectAnimator oa = ObjectAnimator.ofFloat(home_man_iv, "rotationY",
                                new float[]{0f, 60f, 120f, 180f});
                        oa.setDuration(1000);
                        oa.setRepeatCount(0);
                        oa.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                float playTime = (float) animation.getAnimatedValue();
                                if (playTime >= 90) {

                                    home_man_iv.setBackgroundResource(R.drawable.male_b);
                                }
                                if (playTime == 180f) {
                                    count++;
                                    endOther = true;
                                }
                            }
                        });
                        oa.start();
                    } else if (endOther) {
                        endOther = false;
                        ObjectAnimator oa = ObjectAnimator.ofFloat(home_man_iv, "rotationY",
                                new float[]{0f, 60f, 120f, 180f});
                        oa.setDuration(1000);
                        oa.setRepeatCount(0);
                        oa.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                float playTime = (float) animation.getAnimatedValue();
                                if (playTime >= 90) {
                                    home_man_iv.setBackgroundResource(R.drawable.male_f);
                                }
                                if (playTime == 180f) {
                                    count++;
                                    endOther = true;
                                }
                            }
                        });
                        oa.start();
                    }

                }

            }
        });

这里写图片描述

转场动画:
ActivityOptions类作为谷歌提供的转场效果类如果用过的很简单哦。
首先xml里面用android:transitionName作为标记给共享的view。
下面recylerView里面item中item

 <ImageView
     android:transitionName="ivtraname"
     android:id="@+id/item_iv"
     android:layout_width="match_parent"
     android:layout_height="180dp"/>

这个是跳转后的布局里面:

 <ImageView
        android:background="@mipmap/rv0"
        android:transitionName="ivtraname"
        android:scaleType="fitXY"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

sharedElement是ImageView共享View
sharedElementName=tansitionName的名称=ivtraname

public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
            View sharedElement, String sharedElementName) {
        return makeSceneTransitionAnimation(activity, Pair.create(sharedElement, sharedElementName));
    }
@SafeVarargs
    public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
            Pair<View, String>... sharedElements) {

使用也是很简单的:这里我使用的是兼容包类

 ActivityOptionsCompat optionsCompat1 = ActivityOptionsCompat.makeSceneTransitionAnimation((Activity) context,(View)holder.miv,"ivtraname");
                Intent intent = new Intent(context, Main3Activity.class);
                context.startActivity(intent, optionsCompat1.toBundle());//最低兼容16

效果如下:
这里写图片描述
demon地址如下:
https://github.com/luhenchang/Lsn22_SceneTransitionAnimation.git
如果有所不对地方请多多指教,相互学习!!!!
https://github.com/luhenchang/Lsn20_PropertyAnimation.git

展开阅读全文

没有更多推荐了,返回首页