Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性

2024-05-06 13:48

本文主要是介绍Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

动画入门和进阶文章列表:

Animation动画概述和执行原理
Android动画之补间动画TweenAnimation
Android动画之逐帧动画FrameAnimation
Android动画之插值器简介和系统默认插值器
Android动画之插值器Interpolator自定义
Android动画之视图动画的缺点和属性动画的引入
Android动画之ValueAnimator用法和自定义估值器
Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性
Android动画之ObjectAnimator中ofXX函数全解析-自定义Property,TypeConverter,TypeEvaluator
Android动画之AnimatorSet联合动画用法
Android动画之LayoutTransition布局动画
Android动画之共享元素动画
Android动画之ViewPropertyAnimator(专用于view的属性动画)
Android动画之Activity切换动画overridePendingTransition实现和Theme Xml方式实现
Android动画之ActivityOptionsCompat概述
Android动画之场景变换Transition动画的使用
Android动画之Transition和TransitionManager使用
Android动画之圆形揭露动画Circular Reveal

1 ObjectAnimator 概述

前面讲解了ValueAnimator和估值器,ValueAnimator只能对数值进行计算,要实现动画需要监听动画,然后获取数值,自己操作对象。不知道大家的感觉如何,我有两个两个感觉,一是这个动画有点复杂,另一个感觉是虽然叫做属性对象,但是完全没有感受到哪里跟属性有关。本篇文章主要讲解ObjectAnimator对象,这个对象继承自ValueAnimator,可以通过改变对象的属性,实现动画,是不是感觉ObjectAnimator叫做属性对象更合适。

在这里插入图片描述

ObjectAnimator继承自ValueAnimator,也是从API11才开始提供。

ValueAnimator类提供了把动画中的属性设置给目标对象的能力,只不过需要我们设置监听自己进行设置。ObjectAnimator可以设置动画目标对象(构造函数可以直接传入),构造函数中提供了将要作用于目标对象的属性名,ObjectAnimator运行过程中会把提供的属性利用目标对象提供的set函数设置给目标对象,有时也会调用目标对象的get函数获取属性值。简单说就是ObjectAnimator通过不断控制值的变化,再不断自动赋给对象的属性(调用目标对象的setXXX函数),从而实现动画效果。

属性动画原理:
属性动画并不是真正通过改变对象的属性来实现动画,而是通过调用目标对象指定的setXxx方法,其中xxx就是指定的属性名,对象不一定有xxx这个属性,只要有setXxx这个方法就可以。ObjectAnimator动画过程中会调用SetXxx函数设置xxx的值,然后其内部会主动调用invalidate()函数进行不停地重绘,这样就实现了动画效果。

ObjectAnimator类似ValueAnimator,不但可以直接利用代码生成,也可以利用xml文件实例化,xml方式不常用。
XML定义ObjectAnimator的标签为objectAnimator,API23以后也可以使用PropertyValuesHolder,具体使用方式在讲解ValueAnimator时已经讲解,这里不再重复。

ObjectAnimator实现动画的of方法

ofArgb(Object target, String propertyName, int... values)
ofArgb(T target, Property<T, Integer> property, int... values)
ofFloat(Object target, String xPropertyName, String yPropertyName, Path path)
ofFloat(T target, Property<T, Float> property, float... values)
ofFloat(T target, Property<T, Float> xProperty, Property<T, Float> yProperty, Path path)
ofFloat(Object target, String propertyName, float... values)ofInt(T target, Property<T, Integer> xProperty, Property<T, Integer> yProperty, Path path)
ofInt(T target, Property<T, Integer> property, int... values)
ofInt(Object target, String propertyName, int... values)
ofInt(Object target, String xPropertyName, String yPropertyName, Path path)ofMultiFloat(Object target, String propertyName, float[][] values)
ofMultiFloat(Object target, String propertyName, Path path)
ofMultiFloat(Object target, String propertyName, TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, T... values)
ofMultiInt(Object target, String propertyName, int[][] values)
ofMultiInt(Object target, String propertyName, Path path)
ofMultiInt(Object target, String propertyName, TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, T... values)ofObject(T target, Property<T, V> property, TypeEvaluator<V> evaluator, V... values)
ofObject(Object target, String propertyName, TypeConverter<PointF, ?> converter, Path path)
ofObject(T target, Property<T, V> property, TypeConverter<PointF, V> converter, Path path)
ofObject(T target, Property<T, P> property, TypeConverter<V, P> converter, TypeEvaluator<V> evaluator, V... values)
ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values)ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)

2利用ObjectAnimator实现补间动画效果

2.1 平移动画

View有setTranslationX,setTranslationY实现坐标的改变
setTranslationX(float translationX) :以当前控件为原点,在x轴上移动
setTranslationY(float translationY) :以当前控件为原点,在Y轴上移动

ObjectAnimator实现平移:
向X轴正方向移动:

objectAnimator = ObjectAnimator.ofFloat(textView, "translationX", 100, 200, 300,400,500);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new LinearInterpolator());

在这里插入图片描述
Y轴方向移动不在演示

2.2 透明度

View有setAlpha函数控制透明度
ObjectAnimator实现透明度变化:

objectAnimator = ObjectAnimator.ofFloat(textView, "alpha", 0.1f,1.0f);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new LinearInterpolator());

在这里插入图片描述

2.3 缩放

View有setScaleX(float scaleX)和setScaleY(float scaleY)函数对View进行缩放。
ObjectAnimator实现缩放

objectAnimator = ObjectAnimator.ofFloat(textView, "scaleX", 0.1f,1.0f,2.0f,1.0f);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new LinearInterpolator());

在这里插入图片描述

2.4 旋转

View有setRotationX(float rotationX)和setRotationY(float rotationY),setRotation(rotation)函数设置旋转,
setRotationX:绕X轴旋转
setRotationY:绕Y轴旋转
setRotation: 绕中心旋转

ObjectAnimator实现旋转

objectAnimator = ObjectAnimator.ofFloat(textView, "rotation", 0,270);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new LinearInterpolator());

在这里插入图片描述

3 ObjectAnimator动画注意事项:重要

总结来自:https://developer.android.google.cn/guide/topics/graphics/prop-animation#java

动画一些特性:

  • duration 动画运行时长,如果不设置默认300ms
  • interpolation:设置动画运行过程中对应的动画完成状态(设置动画运行速率,类似动画设置了1000ms,可以让动画在运行到100ms时就展示动画完成时的状态)
  • 动画刷新频率,默认是每10ms刷新一次,但也跟系统忙碌程度有关,如果系统资源占用严重可能时间会延长。

重要:一下内容来自androidDeveloper,非常重要请大家关注
属性动画getXxx(),setXxx()函数和属性xxx的规则说明:

  • 如果ObjectAnimator想操作对象的foo属性实现动画操作,对象必须有相应的setFoo函数,
    因为ObjectAnimator会自动根据foo属性对应的setFoo函数去更新属性值。所以可以推测出ObjectAnimator会自动把属性转化成对应的set函数,会强制大写第一个字母,然后反射得到set函数,进行调用,所以ObjectAnimator初始化时属性首字母大小写无所谓,关键是除了首字母其他一定要和set函数对应。
  • 上面我们知道了对象setter函数的作用,那么getter函数有什么用处呢,ObjectAnimator指定values时,可以指定多个value,如果我们初始化时只指定了一个值,ObjectAnimator会把这个值作为动画结束状态的值,此时会调用getter函数作为动画初始状态的值。
  • 动画目标对象getter和setter函数的参数类型和ObjectAnimator设置动画开始和结束值的类型必须相同。
  • ObjectAnimator内部会主动调用目标对象的setter方法,但是这并不会导致view的重绘,需要你在setter方法中主动调用invalidate方法或者设置动画监听函数,在onAnimationUpdate的回调中调用invalidate方法。如果你要自己定义对象的setter方法,就要主动调用invalidate方法。

4 自定义ObjectAnimator属性

上面把view已经存在的平移,旋转,缩放,透明度属性利用ObjectAnimator进行了实现,接着将演示自定义ObjectAnimator属性的操作,通过上面的分析知道ObjectAnimator重要的点是属性和设置属性的set函数,以及主动调用invalidate函数,下面会通过一个例子来实现自定义ObjectAnimator属性的过程。
自定义view

public class ViewDemo22 extends View {private int color = Color.GREEN;private int radius = 100;private Paint mPaint;public int getColor() {return color;}public void setColor(int color) {this.color = color;mPaint.setColor(color);invalidate();}public int getRadius() {return radius;}public void setRadius(int radius) {this.radius = radius;invalidate();}public ViewDemo22(Context context) {this(context,null,0);}public ViewDemo22(Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public ViewDemo22(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setColor(color);mPaint.setStrokeWidth(5);mPaint.setStyle(Paint.Style.STROKE);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(getMeasuredHeight()/2,getMeasuredHeight()/2,radius,mPaint);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = MeasureSpec.getSize(widthMeasureSpec);int height = MeasureSpec.getSize(heightMeasureSpec);if (width < 200){width = 200;}if (height < 200){height = 200;}if (width < height){setMeasuredDimension(height,height);}else{setMeasuredDimension(width,width);}}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);}
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.ldx.canvasdrawdemo.ViewDemo22android:id="@+id/viewdemo"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"/></android.support.constraint.ConstraintLayout>
setContentView(R.layout.activity_main);
viewDemo22 = findViewById(R.id.viewdemo);ObjectAnimator objectAnimator = ObjectAnimator.ofInt(viewDemo22, "radius", 50, 300);
objectAnimator.setDuration(1000);
objectAnimator.setInterpolator(new LinearInterpolator());
objectAnimator.setRepeatCount(-1);
objectAnimator.start();

在这里插入图片描述

改变颜色,没有设置插值器,只是简单数据改变:

ObjectAnimator objectAnimator = ObjectAnimator.ofInt(viewDemo22, "color", Color.RED, Color.GREEN);
objectAnimator.setDuration(1000);
objectAnimator.setInterpolator(new LinearInterpolator());
objectAnimator.setRepeatCount(-1);
objectAnimator.start();

在这里插入图片描述

5 Xml 方式实现

用的不多,只简单举例

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:valueTo="200"android:valueType="floatType"android:propertyName="y"android:repeatCount="1"android:repeatMode="reverse"/>

ObjectAnimator objAnimator = (ObjectAnimator ) AnimatorInflater.loadAnimator(this,
R.animator.animator);

这篇关于Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/964525

相关文章

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja