帧动画android
⑴ Android帧动画/AnimationDrawable导致的OOM/ANR的解决方案
如果有播放超多帧动画的需求,直接点击 FrameAnimation 在github查看,基本能满足你的所有需求,就不用往下看了,基本能满足 99.99% 人的需求。
当在应用中需要使用帧动画的时候,最先想到的就是Android提供的AnimationDrawable了,但是如果帧动画中如果包含上百帧图片,此时再用AnimationDrawable就不是那么理想了。AnimationDrawable使用一个Drawable数组来存储每一帧的图像,会直接把全部图片加载进内存。随着帧数量的增多,就算性能再强劲的机器也会卡顿、OOM。
最近的项目中需要用到大量的帧动画(各种闪瞎24K钛合金狗眼的礼物效果,多的高达200帧),既然AnimationDrawable不行,就想到了两种解决方法。
因为是直播的项目,包含人脸贴图等都是用opengl绘制的,如果用OpenGL绘制一层Texture直接推流还省事。只在主播端处理就行了,但是IOS那边都弄得差不多了,直接原生的不用处理也不会有什么异常什么的。。很尴尬。
好吧,第一个不行那就想到Android自带的surfaceView啦。我首先用不同的手机测试了下应用从本地decode一个bitmap的时间(png格式,414*736,大小在30-100k之间),因为帧动画的每帧不会太大,在性能好点的设备上基本保持在10-30ms之间(不推流基本上推流状态下10ms左右,推流状态下20左右),在性能稍差的设备中基本上也不会超过50ms,所以说是没什么大问题的。
既然不能完全加载到内存,想到的就是类似视频播放或者视频直播类似的思路。首先定义一个Bitmap的缓冲区,边绘制边加载。首先加载一定数量的帧到Bitmap缓冲区,加载完成后通知SurfaceView开始绘制。SurfaceView绘制一帧完成后通知Bitmap缓冲区加载下一帧,同时将绘制过的一帧的从Bitmap缓冲区移除。一帧绘制完成后,绘制线程根据设置的帧间隔休眠一段时间,休眠完成后开始从Bitmap缓冲区获取下一帧,依此类推,一直循环,直到播放完成或者手动停止。按照这种方式实现起来,发现oom卡顿什么的果然不存在了,内存的使用情况如图。
但是看着这个垃圾桶一个挨一个,这个内存回收情况完全不正常!GC太频繁了。想着应该是这里出现了问题。[图片上传失败...(image-96f387-1512626035688)]
频繁的添加移除bitmap,导致了不算太严重的内存抖动。之所以称之为不算太严重,因为大概400ms一次,一次gc花费2ms左右。不看内存,只看运行效果。真的感觉不出来。但是呢,这样显然也是不行滴。
最常见的解决方法就是对象的复用,创建各种pool。Android也提供了Bitmap的复用方式,在加载bitmap的时候传入一个inBitmap,那么加载的bitmap就会复用原bitmap的内存空间,所以理论上将要复用的bitmap和新加载的bitmap在颜色深度一样的情况下,复用的bitmap宽高要大于新加载的bitmap。50L的桶毕竟最多只能装50L的水。关于inBitmap更多资料可以参考 这里 , 还有这里 。(请自备梯子)。 使用起来很简单,大概就是这样
然后实现思路就是在这里修改了,把将要删除的哪一帧留下来作为inBitmap。
⑵ 用 ConstraintLayout 和 ConstraintSet 实现 Android 关键帧动画
关键帧动画是一种动画技术,它通过指定动画开始和结束状态,让系统自动计算并实现动画过程中的过渡状态。在 Android 开发中,利用 ConstraintLayout 和 ConstraintSet 可以轻松实现关键帧动画。
首先,在初始布局中,将要动画展示的组件(如 TextView)放置于屏幕之外,确保动画组件能够覆盖整个屏幕。初始布局中可以设定组件的全部属性,如字体大小、颜色等。
对于最终状态的布局,则只需定义各组件的最终位置。在实际开发中,开发者通常会提前设计并准备好这些布局文件。
接着,利用 TransitionManager 来计算并创建从初始布局到最终布局的动画路径。TransitionManager 默认提供匀速动画,若需自定义动画效果,开发者可以创建自定义的 transition,以实现所需动画。
通过上述步骤,只需寥寥四行代码,即可完成关键帧动画的实现。这不仅简化了动画开发流程,也使得动画效果更加丰富多样。
欲了解更多关于关键帧动画的实现细节,推荐观看 YouTube 视频:Keyframe Animations with ConstraintLayout and ConstraintSet。
⑶ android中的动画有哪几类,它们的特点和区别是什么
在Android中,动画技术的运用为用户界面增添了生动性和交互性。动画可以分为两种主要类型:补间动画和帧动画。
补间动画通过指定一个View的初始状态和目标状态,以及动画变化的时间和方式,来实现图形内容的动态变化。这种动画效果主要包含四种:Alpha动画调整透明度,Scale动画改变大小,Translate动画实现位置移动,Rotate动画进行旋转。
相比之下,帧动画采用预先定义的一系列图像帧,每帧对应动画的一个特定时间点,通过连续播放这些图像帧来构成动画效果。每帧之间的切换时间由开发者设定,以此来控制动画的流畅度和速度。
补间动画和帧动画在实现动画效果时各有优势。补间动画通过动态计算实现平滑过渡,适用于需要自然流畅变化的动画场景;而帧动画通过直接播放预定义的图像序列,适用于需要精确控制每一帧内容和播放速度的动画设计。
理解这两种动画类型的特点与区别对于在Android应用开发中高效利用动画技术至关重要。补间动画适合实现自然流畅的动画效果,而帧动画则适用于需要精确控制每一帧的动画场景。根据具体需求和场景选择合适的动画类型,可以有效提升用户界面的交互性和视觉体验。
⑷ android中的动画有哪几类,它们的特点和区别是什么
Android中的常用动画有三种:
1、View Animation(Tween Animation 补间动画)
动画的对象除了传统的View对象,还可以是Object对象,动画之后,Object对象的属性值被实实在在的改变了。Propertyanimation能够通过改变View对象的实际属性来实现View动画。任何时候View属性的改变,View能自动调用invalidate()来试试刷新。
⑸ android中的动画有哪几类
在Android3.0(即API Level11)以前,Android仅支持2种动画:分别是Frame Animation(逐帧动画)和Tween Animation(补间动画),在3.0之后Android支持了一种新的动画系统,称为:Property Animation(属性动画)。
一、Frame Animation:(逐帧动画)
这个很好理解,一帧帧的播放图片,利用人眼视觉残留原理,给我们带来动画的感觉。它的原理的GIF图片、电影播放原理一样。
1.定义逐帧动画比较简单,只要在中使用子元素定义所有播放帧即可。
(1) android:oneshot 设置是否仅播放一次
(2) android:drawable 设置每一帧图片
(3) android:ration 设置图片间切换间隔
2.习惯上把AnimationDrawable设置为ImageView的背景
android:background=@anim/frame_anim
然后我们就可以在java代码中获取AnimationDrawable对象了
AnimationDrawable anim = (AnimationDrawable)imageView.getBackground();
(需要注意的是,AnimationDrawable默认是不播放的,调用其start()方法开始播放,stop停止播放)
3.上面的动画文件是通过xml文件来配置的,如果你喜欢,也可以通过在java代码中创建AnimationDrawable对象,然后通过addFrame(Drawable frame, int ration)方法向动画添加帧,然后start()。。。
二、Tween Animation:(补间动画)
补间动画就是我们只需指定开始、结束的“关键帧“,而变化中的其他帧由系统来计算,不必自己一帧帧的去定义。
1. Android使用Animation代表抽象动画,包括四种子类:AlphaAnimation(透明度动画)、ScaleAnimation(缩放动画)、TranslateAnimation(位移动画)、RotateAnimation(透明度动画)。Android里面允许在java中创建Animation类对象,但是一般都会采用动画资源文件来定义动画,把界面与逻辑分离
<set android:interpolator="@android:anim/linear_interpolator" xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 定义透明度的变换 -->
<!-- 定义旋转变换 -->
<rotate android:ration="3000/" android:fromdegrees="0" android:pivotx="50%" android:pivoty="50%" android:todegrees="1800">
</rotate></alpha></set>
(一个set可以同时定义多个动画,一起执行。)
2. android:interpolator=@android:anim/linear_interpolator控制动画期间需要补入多少帧,简单来说就是控制动画速度,有些地方翻译为“插值“。Interpolator有几种实现类:LinearInterpolator、AccelerateInterpolator、、CycleInterpolator、DecelerateInterpolator,具体使用可以参考官方API Demo。
3. 定义好anim文件后,我们可以通过AnimationUtils工具类来加载它们,加载成功后返回一个Animation。然后就可以通过View的startAnimation(anim)开始执行动画了。
Animation anim = AnimationUtils.loadAnimation(this, R.anim.anim);
//设置动画结束后保留结束状态
anim.setFillAfter(true);
//设置插值效果
anim.setInterpolator(interpolator);
//对view执行动画
view. startAnimation(anim);
三、Property Animation:(属性动画)
属性动画,这个是在Android 3.0中才引进的,它可以直接更改我们对象的属性。在上面提到的Tween Animation中,只是更改View的绘画效果而View的真实属性是不改变的。假设你用Tween动画将一个Button从左边移到右边,无论你怎么点击移动后的Button,他都没有反应。而当你点击移动前Button的位置时才有反应,因为Button的位置属性木有改变。而Property Animation则可以直接改变View对象的属性值,这样可以让我们少做一些处理工作,提高效率与代码的可读性。
(1)ValueAnimator:包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用ValueAnimator有两个步骤
1计算属性值。
2根据属性值执行相应的动作,如改变对象的某一属性。
我们的主是第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),将要改变View对象属性的事情在该接口中do。
animation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//do your work
}
});
(2)ObjectAnimator:继承自ValueAnimator,要指定一个对象及该对象的一个属性,当属性值计算完成时自动设置为该对象的相应属性,即完成了Property Animation的全部两步操作。实际应用中一般都会用ObjectAnimator来改变某一对象的某一属性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,应该满足以下条件:
1.对象应该有一个setter函数:set(驼峰命名法)
2如下面的例子,像ofFloat之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的getter方法:get
3如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, alpha, 0f, 1f);
oa.setDuration(3000);
oa.start();
如果不满足上面的条件,我们只能乖乖的使用ValueAnimator来创建动画。
(3)Animator.AnimatorListener:可以为Animator设置动画监听,需要重写下面四个方法。
onAnimationStart()
onAnimationEnd()
onAnimationRepeat()
onAnimationCancel()
这里我们也可以实现AnimatorListenerAdapter,他的好处是可以只用定义想监听的事件而不用实现每个函数却只定义一空函数体。如下:
anim.addListener(new AnimatorListenerAdapter() {
public void on AnimationEnd(Animator animation){
//do your work
}
});
(4)AnimationSet:可以组合多个动画共同工作
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(anim1).before(anim2);
bouncer.play(anim2).with(anim3);
bouncer.play(anim2).with(anim4)
bouncer.play(anim5).after(amin2);
animatorSet.start();
上面的代码意思是: 首先播放anim1;同时播放anim2,anim3,anim4;最后播放anim5。
(5)TimeInterplator:与Tween中的interpolator类似。有以下几种
AccelerateInterpolator 加速,开始时慢中间加速
DecelerateInterpolator 减速,开始时快然后减速
先加速后减速,开始结束时慢,中间加速
AnticipateInterpolator 反向 ,先向相反方向改变一段再加速播放
反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
BounceInterpolator 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
CycleIinterpolator 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
LinearInterpolator 线性,线性均匀改变
OvershottInterpolator 回弹,最后超出目的值然后缓慢改变到目的值
TimeInterpolator 一个接口,允许你自定义interpolator,以上几个都是实现了这个接口
(6)Keyframes:可以让我们定义除了开始和结束以外的关键帧。KeyFrame是抽象类,要通过ofInt(),ofFloat(),ofObject()获得适当的KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象,如下:
Keyframe kf0 = Keyframe.ofInt(0, 400);
Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
Keyframe kf3 = Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe(width, kf0, kf1, kf2, kf4, kf3);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn, pvhRotation);
上述代码的意思是:设置btn对象的width属性值使其:开始时 Width=400,动画开始1/4时 Width=200,动画开始1/2时 Width=400,动画开始3/4时 Width=100,动画结束时 Width=500。
(7)ViewPropertyAnimator:对一个View同时改变多种属性,非常推荐用这种。该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图。而且使用起来非常简便,但是要求API LEVEL 12,即Android 3.1以上。仅需要一行代码即可完成水平、竖直移动
myView.animate().translationX(50f). translationY(100f);
(8)常需要改变的一些属性:
translationX,translationY: View相对于原始位置的偏移量
rotation,rotationX,rotationY: 旋转,rotation用于2D旋转角度,3D中用到后两个
scaleX,scaleY: 缩放比
x,y: View的最终坐标,是View的left,top位置加上translationX,translationY
alpha: 透明度
四、最后自己总结一下这三种动画的优缺点:
(1)Frame Animation(帧动画)主要用于播放一帧帧准备好的图片,类似GIF图片,优点是使用简单方便、缺点是需要事先准备好每一帧图片;
(2)Tween Animation(补间动画)仅需定义开始与结束的关键帧,而变化的中间帧由系统补上,优点是不用准备每一帧,缺点是只改变了对象绘制,而没有改变View本身属性。因此如果改变了按钮的位置,还是需要点击原来按钮所在位置才有效。
(3)Property Animation(属性动画)是3.0后推出的动画,优点是使用简单、降低实现的复杂度、直接更改对象的属性、几乎可适用于任何对象而仅非View类,缺点是需要3.0以上的API支持,限制较大!但是目前国外有个开源库,可以提供低版本支持!
⑹ Android 中的动画有哪几类,它们的特点和区别是什么
1.View Animation(Tween Animation):补间动画,给出两个关键帧,通过一些算法将给定属性值在给定的时间内在两个关键帧间渐变。
View animation只能应用于View对象,而且只支持一部分属性,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化.
2.Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影补间动画和帧动画。
补间动画和Frame动画的定义:
所谓补间动画,是指通过指定View的初末状态和变化时间、方式,对View的内容完成一系列的图形变换来实现动画效果。主要包括四种效果:Alpha、Scale、Translate和Rotate。
帧动画就是Frame动画,即指定每一帧的内容和停留时间,然后播放动画。。
3.属性动画
只是一个动画效果,组件其实还在原来的位置上,xy没有改变
###位移:
第一个参数target指定要显示动画的组件
第二个参数propertyName指定要改变组件的哪个属性
第三个参数values是可变参数,就是赋予属性的新的值
传入0,代表x起始坐标:当前x + 0
传入100,代表x终点坐标:当前x + 100
//具有get、set方法的成员变量就称为属性
ObjectAnimator oa = ObjectAnimator.ofFloat(bt, "translationX", 0, 100) ;
4.四种基本的动画 ,透明/伸缩/移动/旋转。
(1)XML中
alpha 渐变透明度动画效果
scale 渐变尺寸伸缩动画效果
translate画面转换位置移动动画效果
rotate画面转移旋转动画效果
(2) JavaCode中
AlphaAnimation渐变透明度动画效果
ScaleAnimation渐变尺寸伸缩动画效果
TranslateAnimation画面转换位置移动动画效果
RotateAnimation画面转移旋转动画效果
(3)Android动画模式
Animation主要有两种动画模式:
一种是tweened animation(渐变动画)
一种是frame by frame(画面转换动画)
Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;
Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。