安卓开发笔记 之 动画

发布于 2025-01-13 19:47:18 字数 3988 浏览 2 评论 0

分三种:view 动画、帧动画、属性动画

view 动画

  1. 平移、旋转、缩放、透明度。可以用 AnimationSet 实现动画的一起播放
  2. 布局动画:
  • layoutAnimation:给 viewgroup 子元素加上出场效果,比如用于 listview
<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.5"
    android:animationOrder="reverse"
    android:animation="@anim/anim_item"/>
  • Activity 切换效果。overridePendingTransition(enterAnim,exitAnim) 它的位置必须在 startActivity 或 finish 后面,否则不生效

帧动画

一系列图片连续播放。尽量避免使用帧动画,使用的话应尽量避免使用过多尺寸较大的图片,防止发生 OOM

属性动画

动画帧率 10ms/帧

ObjectAnimator。它的作用是让对象的属性值在一定时间内完成到另一个属性值的改变。

  1. translationX 和 translationY:控制 view 从它布局容器左上角坐标偏移的位置;
  2. rotation、rotationX 和 rotationY:控制 view 围绕支点进行 2D 和 3D 旋转;
  3. scaleX 和 scaleY:控制 view 围绕着它的支点进行 2D 缩放;
  4. pivotX 和 pivotY:控制支点位置,围绕这个支点进行旋转和缩放处理。默认情况下,支点是 view 的中心点;
  5. x 和 y:控制 view 在它的容器中的最终位置,它是最初的左上角坐标和 translationX、translationY 的累计和;
  6. alpha:控制透明度,默认是 1(不透明)。

原理:

通过 ObjectAnimator 的静态工厂方法直接返回一个 ObjectAnimator 对象,参数包括 view 对象,以及 view 的属性名字, 这个属性必须要有 get/set 方法 ,因为 ObjectAnimator 内部会 通过反射机制 来修改属性值。 getXX() 用于读取初始值,如果给定初始值可以没有 getXX();ObjectAnimator 不断的调用 setXX() 调整该属性值,然后 invalidate,在这个时间内所传递的值越来越接近最终值,不断循环重复直到达到结束值,因此 setXX() 必须有

特殊情况

比如 TextiView 继承自 View,也有 setWidth(),但是该方法用于设置最大最小宽度而不是当前宽度,因此再使用属性动画不会 crash 但不会有效果。可这样解决:

  • 使用装饰者模式,为该对象加上 get/set 方法
class ViewWrapper{
	private View mTarget;
	public ViewWrapper(View target){
		mTarget = target;
	}
	
	public void setWidth(int width){
		mTarget.getLayoutParams().width = width;
		//	千万别忘了
		mTarget.requestLayout();
	}
	
	public int getWidth(){
		return mTarget.getLayoutParams().width;
	}
}

这里通过操作 LayoutParams 来改变 width 属性,之后再 requestLayout 重新测量、布局。当然也可以通过 LayoutParams 修改 边距、其他 view 属性。

  • 使用 ValueAnimator 监听器,自己实现属性的改变
ValueAnimator animator = ValueAnimator.ofFloat(0,100);
animator.setTarget(view);
animator.setDuration(1000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Float value = (Float) animation.getAnimatedValue();
        //do the animation!
    }
});

插值器和估值器

属性动画实现非匀速动画的重要手段

  • 时间插值器(TimeInterpolator) 的作用是根据时间流逝的百分比计算出当前属性值改变的百分比,系统内置的插值器有线性插值器(LinearInterpolator)、加速减速插值器(AccelerateDecelerateInterpolator) 和减速插值器(DecelerateInterpolator)。
  • 类型估值器(TypeEvaluator) 的作用是根据当前属性改变的百分比计算出改变后的属性值,系统内置的估值器有 IntEvaluator、FloatEvaluator 和 ArgbEvaluator。可用于颜色渐变

requestLayout 和 invalidate 区别

  1. view 不停找 parent 可以一直找到 DecorView,但是还有个 ViewRootImpl。ViewRootImpl 不是一个 View 或者 ViewGroup,他有个成员 mView 是 DecorView,所有的操作从 ViewRootImpl 开始自上而下分发
  2. view 的 invalidate 不会导致 ViewRootImpl 的 invalidate 被调用,而是递归调用父 view 的 invalidateChildInParent,直到 ViewRootImpl 的 invalidateChildInParent,然后触发 peformTraversals,会导致当前 view 被重绘,由于 mLayoutRequested 为 false,不会导致 onMeasure 和 onLayout 被调用,而 OnDraw 会被调用
  3. 一个 view 的 invalidate 会导致本身 PFLAG_INVALIDATED 置 1,导致本身以及父族 viewgroup 的 PFLAG_DRAWING_CACHE_VALID 置 0
  4. requestLayout 会直接递归调用父窗口的 requestLayout,直到 ViewRootImpl,然后触发 peformTraversals,由于 mLayoutRequested 为 true,会导致 onMeasure 和 onLayout 被调用。不一定会触发 OnDraw
  5. requestLayout 触发 onDraw 可能是因为在在 layout 过程中发现 l,t,r,b 和以前不一样,那就会触发一次 invalidate,所以触发了 onDraw,也可能是因为别的原因导致 mDirty 非空(比如在跑动画)
  6. requestLayout 会导致自己以及父族 view 的 PFLAG_FORCE_LAYOUT 和 PFLAG_INVALIDATED 标志被设置。
  7. 参考

invalidate 和 postInvalidate 是同步异步的区别(联想 handler.postXXX ​)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

冰魂雪魄

暂无简介

文章
评论
25 人气
更多

推荐作者

最终幸福

文章 0 评论 0

与酒说心事

文章 0 评论 0

┈┾☆殇

文章 0 评论 0

梦醒灬来后我

文章 0 评论 0

念﹏祤嫣

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文