Android里的动画(补间动画,帧动画,属性动画)
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"/> <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() { @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... 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
更多相关文章
- Android图形---OpenGL(三)
- [置顶] 关于代码家(干货集中营)共享知识点汇总系列——Android
- Android共享动画兼容实现
- Android(安卓)动画之ScaleAnimation应用详解
- Android(安卓)多个 Activity 调用 跳转
- android View各属性详解
- Android(安卓)的 ListView 的CheckBox标题栏显示文本之后显示单
- android 文字图片合成
- 给Activity切换加入动画