动画

一、补间动画(Tweened Animation)

作用对象:视图控件View

原理: 通过确定开始的视图样式以及结束的视图样式,中间的动画变化过程有系统补全来确定一个动画

优点:简单、方便,已封装好基础动画效果

缺点:仅控制整体实体效果,无法控制属性

动画样式: 平移动画(Translate)缩放动画(scale)旋转动画(rotate)透明度动画(alpha)

应用场景:视图中,标准、基础的动画效果。Activity,Fragment的切换效果。ViewGroup中子元素的出场效果

数值上的理解:从-100到100的值,以“%”结尾,表示百分比相对于自身;从-100到100的值,以“%p”结尾,表示百分比相对于父容器。例如平移开始位置在自身中间则是50%,如平时开始位置在父容器的则是50%p

1.平移动画(Translate)

TranslateAnimation类

示例代码:

android:duration = "3000"
android:fromXDelta="0"
android:toXDelta="300"
android:fillBefore = "false"
android:fillAfter = "true"
/>

如上代码中,虽然通过fillBefore,fillAfter设置了停留在动画之后,但是控件还是在原来位置,点击动画后的位置无反应。如果不设置fillBefore,fillAfter,动画结束后会还是显示在动画前的位置

Java代码中使用

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
var translateAnim = AnimationUtils.loadAnimation(this,R.anim.view_anim)
tv_content.startAnimation(translateAnim)
tv_content.setOnClickListener {
Toast.makeText(this, "好的", Toast.LENGTH_SHORT).show()
}
}

纯Java代码:

var translateAnim = TranslateAnimation(0f,500f,0f,0f)
translateAnim.duration = 3000
tv_content.startAnimation(translateAnim)

2.缩放动画(Scale)

ScaleAnimation类

xml定义

android:fromXScale="0.0"
android:toXScale="1.4"
android:fromYScale="0.0"
android:toYScale="1.4"
android:pivotX="50%"
android:pivotY="50%"
android:duration = "3000">

注意:fromXScale和fromYScale都要写,pivotX只是改变开始缩放的始点,不加缩放的始点是view的左上角,

android:pivotX="50"是控件view的x方向上加50像素

android:pivotX="50%"是控件view的x方向上加view控件宽的50%

android:pivotX="50%p"是控件view的x方向上加父布局控件宽的50%

3.旋转动画(Rotate)

RotateAnimation类

android:fromDegrees="0"
android:toDegrees="180"
android:duration = "2000"
android:pivotX="50%"
android:pivotY="50%"
/>
android:fromDegrees="0" // 动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)

4.透明度动画(Alpha)

AlphaAnimation类
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration = "2000">

Activity的切换效果

实现效果从右向左滑动

in_from_right.xml
android:duration = "500"
android:fromXDelta="100%p"
android:toXDelta="0%p"
/>
out_to_left.xml
>
android:duration="500"
android:fromXDelta="0%p"
android:toXDelta="-100%p"
/>

一般用在Activity的成对出现,但至少保持动画时间是一样的

首先要了解Activity的位置

x = 0%p是代表Activity刚好在屏幕中间

x = 100%p是代表Activity在屏幕的右侧

x = -100%p是代表Activity在屏幕的左侧

Fragment的切换效果(几乎用不到)

// 采用`FragmentTransavtion`的 setCustomAnimations()进行设置
FragmentTransaction fragmentTransaction = mFragmentManager
.beginTransaction();
fragmentTransaction.setCustomAnimations(
R.anim.in_from_right,
R.anim.out_to_left);

// 此处的自定义动画效果同Activity,此处不再过多描述

组合动画

采用< Set/>标签

监听动画

anim.addListener(new AnimatorListenerAdapter() {
// 向addListener()方法中传入适配器对象AnimatorListenerAdapter()
// 由于AnimatorListenerAdapter中已经实现好每个接口
// 所以这里不实现全部方法也不会报错
@Override
public void onAnimationStart(Animator animation) {
// 如想只想监听动画开始时刻,就只需要单独重写该方法就可以
}
});

二、逐帧动画(Frame Animation)

作用对象:视图控件View

原理:将动画拆分为帧的形式,且定义每一帧是一张图片,按顺序播放

特点:优点:简单、方便

缺点:容易引起OOM,因会用大量以及尺寸较大的图片资源

应用场景: 较为复杂的个性化动画效果

三、属性动画(Property Animation)

作用对象:任意Java对象

原理: 在一定时间间隔内,通过不断改变值以及赋值给对象的属性,从而实现该对象在该属性上的动画效果

特点:优点:作用对象进行了拓展:不只是View对象,甚至无对象也可以,不只是4种基本变换,还有其他动画效果

缺点:用起来稍微复杂点

应用场景: 与属性相关、更加复杂的动画效果,比如通过改变View的颜色属性达到的动画效果

逐帧动画和补间动画存在一定的缺点:

1:作用对象局限于View

即补间动画只能作用View上,没法对非View的对象进行操作。有些情况的动画效果只是视图的某个属性,比如通过视图的颜色动态变化,从而实现动画效果,而不是针对整个View视图进行动画操作

2:没有改变View的属性,只是改变视觉效果

如移动View,虽然看起来View的位置变了,但实际没变,还是原来的

3:动画效果单一

补间动画只能实现平移、旋转、缩放 & 透明度这些简单的动画需求,一旦遇到相对复杂的动画效果,即超出了上述4种动画效果,那么补间动画则无法实现

ValueAnimator类

原理:通过不断控制值的变化,再不断手动赋给对象的属性,从而实现动画效果

Java代码:正常流程

Log.i("tv_content",tv_content.width.toString()+"\t"+tv_content.layoutParams.width)
//value动画
val valueAnimator = ValueAnimator.ofInt(tv_content.layoutParams.width,500)
valueAnimator.duration = 2000
valueAnimator.addUpdateListener {
val currentValue:Int = it.animatedValue as Int
println(currentValue)
//获取不断改变的值给view相应的属性
tv_content.layoutParams.width = currentValue
tv_content.requestLayout()
}
valueAnimator.start()

在xml中定义

android:valueFrom="0"
android:valueTo="100"
android:valueType="intType"
android:duration="2000"
/>

java用xml中定义的

//用xml的value动画
var valueAnimator = AnimatorInflater.loadAnimator(this,R.animator.value_anim)
valueAnimator.setTarget(tv_content)
valueAnimator.start()

注:有点坑地方补间动画xml的文件夹名是anim,属性动画是animator。第二单纯这样setTarget(view)是没用的,它不知道改变什么属性。

所以用属性动画还是用java代码定义写方便

对象:ValueAnimator.ofObject()

作用:将初始值以对象的形式过渡到结束值,即通过操作对象实现动画效果

需我们自定义TypeEvaluator来告知系统如何进行从初始对象过渡到结束对象的逻辑

示例PointEvaluator.java

// 实现TypeEvaluator接口
public class PointEvaluator implements TypeEvaluator {
// 复写evaluate()
// 在evaluate()里写入对象动画过渡的逻辑
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
// 将动画初始值startValue 和 动画结束值endValue 强制类型转换成Point对象
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
// 根据fraction来计算当前动画的x和y的值
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
// 将计算后的坐标封装到一个新的Point对象中并返回
Point point = new Point(x, y);
return point;
}
}

估值器(TypeEvaluator)

作用:设置动画 如何从初始值 过渡到 结束值 的逻辑

ObjectAnimator类

是ValueAnimator的子类

是通过反射找到相应的set函数

原理:通过不断控制值的变化,再不断自动赋给对象的属性,从而实现动画效果

示例代码:

ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationX",0,270,0);
animator.setDuration(2000);
animator.start();

怎么知道哪些属性是能赋值改变形成动画的呢

1、要使用ObjectAnimator来构造对画,要操作的控件中,必须存在对应的属性的set方法

2、setter 方法的命名必须以骆驼拼写法命名,即set后每个单词首字母大写,其余字母小写,即类似于setPropertyName所对应的属性为propertyName

简单来说:先找View的set相应属性试试,有,就把属性开头大写改为小写即可

自定义ObjectAnimator属性

public class MyPointView extends View {
private PointRadius mPoint = new PointRadius(100);
public MyPointView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mPoint != null) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(300, 300, mPoint.getRadius(), paint);
}
}
void setPointRadius(int radius) {
mPoint.setRadius(radius);
invalidate();
}
}

关键setPointRadius方法

使用:

val objectAnimator = ObjectAnimator.ofInt(my_point_view,"pointRadius",0,300,200)
objectAnimator.duration = 2000
objectAnimator.start()