这里写目录标题
- 前言
- 一、视图动画
- 1. 补间动画---Animation抽象类动画
- 1.1 AlphaAnimation:控制一个对象透明度的动画。
- 1.1.1 xml实现示例
- 1.1.2 java实现示例
- 1.2 RotateAnimation:控制一个对象旋转的动画。
- 1.1.1 xml实现示例
- 1.1.2 java实现示例
- 1.3 ScaleAnimation:控制一个对象尺寸的动画。
- 1.1.1 xml实现示例
- 1.1.2 java实现示例
- 1.4 TranslateAnimation:控制一个对象位置的动画。
- 1.1.1 xml实现示例
- 1.1.2 java实现示例
- 1.5 AnimationSet:代表着一组可以一起播放的动画(最常用)
- 1.1.1 xml实现示例
- 1.1.2 java实现示例
- 2. 帧动画--AnimationDrawable类动画
- 2.1 xml实现示例
- 2.2 java实现示例
- 二、属性动画
- 1. ValueAnimator
- 1.1 透明度动画示例
- 1.2 背景色动画示例
- 1.3 透明度+缩放动画示例((自定义求解器))
- 2. ObjectAnimator
- 2.1 水平移动动画示例
- 2.2 水平缩放动画示例
- 2.3 透明度动画示例
- 2.4 旋转动画示例
- 2.5 坐标移动动画示例
- 2.6 背景颜色动画示例
- 2.7 多动画并行执行示例
- 3. AnimatorSet
- 三、LayoutTransition入门案例
- 3.1 核心点
- 3.2 使用案例
- 四、后记
前言
Android动画可以说是老生常谈了,一个Android相机的UI想要炫酷,肯定离不开动画,现在也有很多现成的动画库,如果想要看懂这些库是如何实现的,或者说想自己不借助其它库,给自己的APP添加点动画,那就不得不懂Android最本质的两种动画了,这两种动画就是视图动画和属性动画,本文通过详细的示例代码对这两种动画资源进行讲解。最后顺带一下LayoutTransition类如何实现布局动画。
官方概述地址
一、视图动画
视图动画包括补间动画和帧动画两种,如名称一样,视图动画只是对View进行视觉上的移动,旋转,缩放,透明度的效果,如果一个带点击事件的View,通过视图动画从A位置移动到B位置,那么你点击B位置是无法触发View的事件的,因为你只有点击View最初的位置即A位置,才能真正点的到这个View。
1. 补间动画—Animation抽象类动画
- 补间动画是指我们只需要给定一个范围的起点值和终点值,起点和终点之间的值由插值算法计算而得。
- 补间动画可以动画XML实现,也可以通过Java代码构建。
- 补间动画都继承自Animation抽象类,主要包括以下4种,下面通过示例代码进行逐一介绍。
1.1 AlphaAnimation:控制一个对象透明度的动画。
1.1.1 xml实现示例
- 在res/anim文件下创建 root element为alpha的资源文件
<?xml version="1.0" encoding="utf-8"?>
<!--
android:duration="2000" 动画时常为2秒
android:fromAlpha="1.0" 动画开始透明度
android:toAlpha="0.0" 动画结束透明度
android:interpolator 透明度从开始值都结束值的变化过程也可以选择具体的插值方法来决定。
-->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"/>
- 给具体的View应用动画
ImageView imageView=findViewById(R.id.testImg);
AlphaAnimation alphaAnimation = (AlphaAnimation) AnimationUtils.loadAnimation(this, R.anim.alpha);
imageView.setAnimation(alphaAnimation);
1.1.2 java实现示例
private AlphaAnimation alphaAnimation()
{
//构造函数传入透明度开始值和结束值
AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f, 1.0f);
//设置动画时常
alphaAnimation.setDuration(2000);
//设置动画的插值算法
alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
return alphaAnimation;
}
//应用动画
imageView.setAnimation(alphaAnimation());
1.2 RotateAnimation:控制一个对象旋转的动画。
1.1.1 xml实现示例
- 在res/anim文件下创建 root element为rotate的资源文件
<?xml version="1.0" encoding="utf-8"?>
<!--
android:fromDegrees="0" 旋转前的角度
android:toDegrees="45" 旋转后的角度
android:pivotX="50%" 旋转的中心点x(%代表是相对于应用动画View的本身,%p代表是相对于应用动画的父控件)
android:pivotY="50%" 旋转的中心点y(%代表是相对于应用动画View的本身,%p代表是相对于应用动画的父控件)
android:duration="2000" 动画持续时长2秒
也可以使用插值控制角度变化的过程,此处省略
-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="45"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"/>
- 给具体的View应用动画
ImageView imageView=findViewById(R.id.testImg);
RotateAnimation rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation(this, R.anim.rotate);
imageView.setAnimation(rotateAnimation);
1.1.2 java实现示例
private RotateAnimation rotateAnimation()
{
/**
* public RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue,
* int pivotYType, float pivotYValue)
* fromDegrees 旋转前的角度
* toDegrees 旋转后的角度
* pivotXType 中心点类型:是相对于View本身(Animation.RELATIVE_TO_SELF)还是相对于View的父控件(Animation.RELATIVE_TO_PARENT)
* pivotXValue 旋转中心点的相对位置x
* pivotYType 中心点类型
* pivotYValue 旋转中心点的相对位置y
*/
RotateAnimation rotateAnimation = new RotateAnimation(0.0f, 45.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//动画时长
rotateAnimation.setDuration(2000);
//是否将View保留在动画旋转后的状态
rotateAnimation.setFillAfter(true);
//设置插值方法
rotateAnimation.setInterpolator(new AccelerateInterpolator());
return rotateAnimation;
}
//应用动画
imageView.setAnimation(rotateAnimation());
1.3 ScaleAnimation:控制一个对象尺寸的动画。
1.1.1 xml实现示例
- 在res/anim文件下创建 root element为scale的资源文件
<?xml version="1.0" encoding="utf-8"?>
<!--
android:fromXScale="1.0" 变化前的相对尺寸比例X
android:fromYScale="1.0" 变化前的相对尺寸比例Y
android:toXScale="2.0" 变化前的相对尺寸比例X
android:toYScale="0.5" 变化前的相对尺寸比例Y
android:pivotY="50%" 旋转的中心点x(%代表是相对于应用动画View的本身,%p代表是相对于应用动画的父控件)
android:pivotX="50%" 旋转的中心点y(%代表是相对于应用动画View的本身,%p代表是相对于应用动画的父控件)
android:duration="2000" 动画时长
-->
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:toXScale="2.0"
android:toYScale="0.5"
android:pivotY="50%"
android:pivotX="50%"
android:duration="2000"/>
- 给具体的View应用动画
ImageView imageView=findViewById(R.id.testImg);
ScaleAnimation scaleAnimation = (ScaleAnimation) AnimationUtils.loadAnimation(this, R.anim.scale);
imageView.setAnimation(scaleAnimation);
1.1.2 java实现示例
private ScaleAnimation scaleAnimation()
{
/**
* ScaleAnimation(float fromX, float toX, float fromY, float toY,
* int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
* fromX 对应xml的fromXScale
* toX 对应xml的toXScale
* fromY 对应xml的fromYScale
* toY 对应xml的toYScale
* pivotXType 与上面rotate的意义一样
* pivotXValue 与上面rotate的意义一样
* pivotYType 与上面rotate的意义一样
* pivotYValue 与上面rotate的意义一样
*/
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 2.0f, 1.0f, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(2000);
scaleAnimation.setFillAfter(true);
scaleAnimation.setInterpolator(new DecelerateInterpolator());
return scaleAnimation;
}
//应用动画
imageView.setAnimation(scaleAnimation());
1.4 TranslateAnimation:控制一个对象位置的动画。
1.1.1 xml实现示例
- 在res/anim文件下创建 root element为translate的资源文件
<?xml version="1.0" encoding="utf-8"?>
<!--
android:fromXDelta="0" 对象移动前x的相对位置
android:fromYDelta="0" 对象移动前y的相对位置
android:toXDelta="92%p" 对象移动后x的相对位置(因为是%p,因此相对的对象的父布局)
android:toYDelta="0" 对象移动后y的相对位置
android:duration="2000" 动画持续时常
-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="92%p"
android:toYDelta="0"
android:duration="2000"/>
- 给具体的View应用动画
ImageView imageView=findViewById(R.id.testImg);
TranslateAnimation translateAnimation = (TranslateAnimation) AnimationUtils.loadAnimation(this, R.anim.translate);
imageView.setAnimation(translateAnimation);
1.1.2 java实现示例
private TranslateAnimation translateAnimation()
{
/**
* public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
* int fromYType, float fromYValue, int toYType, float toYValue)
* fromXType 移动前X的相对位置类型(同scale和rotate的pivotXType),Animation.RELATIVE_TO_PARENT代表相对于View的父布局,Animation.RELATIVE_TO_SELF代表相对于View本身
* fromXValue 移动前X的相对位置
* toXType 与fromXType含义类似
* toXValue 移动后X的相对位置
* fromYType 与fromXType含义类似
* fromYValue 移动前Y的相对位置
* toYType 与fromXType含义类似
* toYValue 移动后Y的相对位置
*/
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.f, Animation.RELATIVE_TO_PARENT, 0.96f, Animation.RELATIVE_TO_PARENT, 0f, Animation.RELATIVE_TO_PARENT, 0.f);
//设置动画时常
translateAnimation.setDuration(2000);
//设置是否将View的位置保留在动画之后的状态
translateAnimation.setFillAfter(true);
//设置插值算法
translateAnimation.setInterpolator(new DecelerateInterpolator());
return translateAnimation;
}
//应用动画
imageView.setAnimation(translateAnimation());
1.5 AnimationSet:代表着一组可以一起播放的动画(最常用)
上面我们讲解了4种动画效果(透明度,选择,缩放,移动),但上面的方法只能对控件应用一个动画,如果想要控件同时具备好几种动画,就可以采用AnimationSet,它就是把上面4种动画融合起来一起使用。
1.1.1 xml实现示例
- 在res/anim文件下创建 root element为set的资源文件
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:shareInterpolator="false">
<!--向集合中添加一个缩放动画-->
<scale
android:duration="2000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:toXScale="2.0"
android:toYScale="0.5"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"/>
<!--向set集合中再套一个set集合-->
<set
android:duration="1000"
android:startOffset="1000"
android:interpolator="@android:anim/accelerate_interpolator">
<!--添加一个缩放动画-->
<scale
android:fromXScale="2.0"
android:fromYScale="0.5"
android:toXScale="0.0"
android:toYScale="0.0"
android:pivotY="50%" android:pivotX="50%"/>
<!--添加一个旋转动画-->
<rotate
android:fromDegrees="0"
android:toDegrees="-45"
android:pivotX="50%"
android:pivotY="50%"/>
</set>
</set>
- 给具体的View应用动画
ImageView imageView=findViewById(R.id.testImg);
AnimationSet animation = (AnimationSet) AnimationUtils.loadAnimation(this, R.anim.set);
imageView.setAnimation(animation);
1.1.2 java实现示例
//用Java代码实现xml中的配置
private AnimationSet animationSet()
{
//创建动画集set
//public AnimationSet(boolean shareInterpolator)
//shareInterpolator:因为set中包含很多种动画,因此需要判断当前set的插值算法是否应用到set中所有动画上
AnimationSet animationSet = new AnimationSet(false);
animationSet.setFillAfter(true);
//创建缩放动画
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 2.0f, 1.0f, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
scaleAnimation.setDuration(2000);
//将缩放动画添加到动画集中
animationSet.addAnimation(scaleAnimation);
//创建子动画集set
AnimationSet animationSubSet = new AnimationSet(true);
animationSubSet.setStartOffset(1000);
animationSubSet.setDuration(1000);
animationSubSet.setInterpolator(new AccelerateInterpolator());
//创建缩放动画
ScaleAnimation scaleAnimation1 = new ScaleAnimation(2.0f, 0.0f, 0.5f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//添加到子动画集中
animationSubSet.addAnimation(scaleAnimation1);
//创建选择动画
RotateAnimation rotateAnimation = new RotateAnimation(0.0f, -45.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//添加到子动画集中
animationSubSet.addAnimation(rotateAnimation);
//将子动画集添加到动画集中
animationSet.addAnimation(animationSubSet);
return animationSet;
}
//应用动画
imageView.setAnimation(animationSet());
2. 帧动画–AnimationDrawable类动画
上一节的补间动画是通过插值的方法将两个要素中间的部分插值出数据。本节讲解的帧动画是不用插值出数据,而是每一帧图片都由我们自己指定。
2.1 xml实现示例
- 在res/drawable文件下创建 root element为animation-list的资源文件
<?xml version="1.0" encoding="utf-8"?>
<!--
android:drawable 指定每帧的图片
android:duration 每帧图片的播放时长
-->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/pic1" android:duration="100"/>
<item android:drawable="@drawable/pic2" android:duration="100"/>
<item android:drawable="@drawable/pic3" android:duration="100"/>
<item android:drawable="@drawable/pic4" android:duration="100"/>
<item android:drawable="@drawable/pic5" android:duration="100"/>
<item android:drawable="@drawable/pic6" android:duration="100"/>
<item android:drawable="@drawable/pic7" android:duration="100"/>
<item android:drawable="@drawable/pic8" android:duration="100"/>
<item android:drawable="@drawable/pic9" android:duration="100"/>
<item android:drawable="@drawable/pic10" android:duration="100"/>
</animation-list>
- 给具体的View应用动画
ImageView img = findViewById(R.id.testFrame);
img.setBackgroundResource(R.drawable.frame);
AnimationDrawable background = (AnimationDrawable) img.getBackground();
background.start();
2.2 java实现示例
private AnimationDrawable animationDrawable()
{
AnimationDrawable animationDrawable = new AnimationDrawable();
try {
//添加帧图片,同时设置每帧播放时间
for (int i = 1; i <= 10; i++) {
Field background = R.drawable.class.getField("pic"+i);
int res_id = background.getInt(background.getName());//通过反射获取资源id
animationDrawable.addFrame(ContextCompat.getDrawable(this,res_id),100);//添加帧数据
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return animationDrawable;
}
//给view应用帧动画
AnimationDrawable animationDrawable = animationDrawable();
img.setBackground(animationDrawable);
animationDrawable.start();
二、属性动画
属性动画比上面介绍的视图动画(补间动画,帧动画)更加灵活,适用范围更广,最重要的是视图动画只是视觉上一个动画,本质位置没有发生变化,比如一个View通过补间动画移动到了某个位置,你点击当前位置是无法触发它的点击事件的,而通过属性动画可以触发。
1. ValueAnimator
ValueAnimator继承自Animator,通过ValueAnimator可以计算给定的起点值和终点值在一段时间内各个时间点的变化值,通过将各个时间点的变化值设置到View的透明度,缩放,旋转,位移,背景颜色,背景图片等等属性上,达到View动画的效果。
ValueAnimator使用时只需要选择求解器(继承自TypeEvaluator)并指定起点值和终点值,但常用的ofFloat和ofInt内部都有默认的求解器,因此不需要自己指定,当然我们也可以自定义求解器。
1.1 透明度动画示例
ValueAnimator alphaAnimator = ValueAnimator.ofFloat(1.0f, 0.5f);
alphaAnimator.setDuration(2000);
alphaAnimator.start();
alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(@NonNull ValueAnimator animation) {
//动态计算一段时间内值的变化
Log.d(TAG, "onAnimationUpdate Float: "+animation.getAnimatedValue());
//将该值设置给View属性
imageView.setAlpha((Float) animation.getAnimatedValue());
}
});
1.2 背景色动画示例
ValueAnimator colorAnimator = ValueAnimator.ofArgb(0xffff00ff, 0xffffff00, 0xffff00ff);
colorAnimator.setDuration(2000);
colorAnimator.start();
colorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(@NonNull ValueAnimator animation) {
Log.d(TAG, "onAnimationUpdate Argb: "+animation.getAnimatedValue());
imageView.setBackgroundColor((Integer) animation.getAnimatedValue());
}
});
1.3 透明度+缩放动画示例((自定义求解器))
ValueAnimator objectAnimator = ValueAnimator.ofObject(new MyEvaluator(), new AlphaScaleObject(1, 1), new AlphaScaleObject(0, 2));
objectAnimator.setDuration(3000);
objectAnimator.start();
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(@NonNull ValueAnimator animation) {
AlphaScaleObject animatedValue = (AlphaScaleObject) animation.getAnimatedValue();
Log.d(TAG, "onAnimationUpdate: Object"+animatedValue.toString());
imageView.setAlpha(animatedValue.alphaValue);
imageView.setScaleType(ImageView.ScaleType.CENTER);
imageView.setScaleX(animatedValue.scaleValue);
imageView.setScaleY(animatedValue.scaleValue);
}
});
//自定义求值器
class MyEvaluator implements TypeEvaluator<AlphaScaleObject>
{
// 属性动画封装了一个因子fraction,我们设置动画时需要setDuration(xxxx),例如时间为1000ms,那么当到达100ms时,fraction就为0.1
// fraction也就是当前时间占总时间的百分比,startValue和endValue就是我们传入的初始值和结束值
@Override
public AlphaScaleObject evaluate(float fraction, AlphaScaleObject startValue, AlphaScaleObject endValue) {
//计算某个时刻的alpha值和scale值
float currAlphaValue= startValue.alphaValue+(endValue.alphaValue-startValue.alphaValue)*fraction;
float currScaleValue= startValue.scaleValue+(endValue.scaleValue-startValue.scaleValue)*fraction;
return new AlphaScaleObject(currAlphaValue,currScaleValue);
}
}
class AlphaScaleObject
{
float alphaValue;//透明度变化值
float scaleValue;//缩放变化值
public AlphaScaleObject(float alphaValue, float scaleValue) {
this.alphaValue = alphaValue;
this.scaleValue = scaleValue;
}
@Override
public String toString() {
return "AlphaScaleObject{" +
"alphaValue=" + alphaValue +
", scaleValue=" + scaleValue +
'}';
}
}
2. ObjectAnimator
ObjectAnimator继承自ValueAnimator,因此它本质还是ValueAnimator,只是ValueAnimator的使用比较麻烦,因为ValueAnimator每次都要在监听函数中监听每个时刻的数据,然后设置给View动画属性,这个过程比较麻烦,代码也不简洁,因此ObjectAnimator对其进行了封装,方便开发者编写更简要的代码。
2.1 水平移动动画示例
/**
* public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)
* target: 需要作用动画的View
* propertyName:通过反射的方式执行view中propertyName的set方法。
* 如想要在X轴上移动View倒霉指定位置,需要执行View中的setTranslationX方法,
* 因此propertyName设置为translationX即可。
*/
ObjectAnimator translationX = ObjectAnimator.ofFloat(imageView, "translationX", 0, 300, -100, 200, -50, 0);
translationX.setDuration(2000);
translationX.setRepeatCount(10);
translationX.start();
2.2 水平缩放动画示例
ObjectAnimator scaleX = ObjectAnimator.ofFloat(imageView, "scaleX", 0f, 1.5f, 2f, 1.5f, 0f, 0.5f, 0.2f, 1f);
imageView.setScaleType(ImageView.ScaleType.CENTER);
scaleX.setDuration(2000);
scaleX.start();
2.3 透明度动画示例
ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 0.5f, 1.0f);
alpha.setDuration(2000);
alpha.start();
2.4 旋转动画示例
ObjectAnimator rotation = ObjectAnimator.ofFloat(imageView, "rotation", 0, 180, 0, -180, 0);
rotation.setDuration(2000);
rotation.start();
2.5 坐标移动动画示例
//贝塞尔曲线动画
Path path = new Path();
path.quadTo(800, 200, 800, 800);
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "x", "y", path);
animator.setDuration(4000);
animator.start();
2.6 背景颜色动画示例
//改变颜色动画
ObjectAnimator backgroundColor = ObjectAnimator.ofArgb(imageView, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
backgroundColor.setDuration(4000);
backgroundColor.start();
2.7 多动画并行执行示例
//多个动画一起执行(AnimatorSet也能实现该功能)
PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("Rotation", 90, -90, 45, -45, 60, -60);
PropertyValuesHolder colorHolder = PropertyValuesHolder.ofInt("BackgroundColor", 0xff55aa11, 0xff115633, 0xff123344, 0xffaabbcc);
PropertyValuesHolder scaleXHolder = PropertyValuesHolder.ofFloat("ScaleX", 1f, 1.1f, 1.2f, 1.5f, 1.8f, 1.5f, 1.2f, 1.1f, 1);
PropertyValuesHolder scaleYHolder = PropertyValuesHolder.ofFloat("ScaleY", 1f, 1.1f, 1.2f, 1.5f, 1.8f, 1.5f, 1.2f, 1.1f, 1);
ObjectAnimator objectAnimator1 = ObjectAnimator.ofPropertyValuesHolder(imageView, rotationHolder, colorHolder, scaleXHolder, scaleYHolder);
objectAnimator1.setDuration(3000);
objectAnimator1.setInterpolator(new AccelerateInterpolator());
objectAnimator1.start();
3. AnimatorSet
AnimatorSet继承自Animator,通过AnimatorSet您可以根据一个动画开始或结束的时间来播放另一个动画,可以指定是同时播放动画、按顺序播放还是在指定的延迟时间后播放。其实就是对上面两种属性动画的操作入口,比较简单,看下API就知道怎么使用了。
AnimatorSet接口文档
三、LayoutTransition入门案例
搞懂了上面讲解的属性动画和视图动画,再看LayoutTransition不要太简单,只是对属性动画和视图动画再次调用而已。
3.1 核心点
LayoutTransition可以在ViewGroup对象的布局变化时启用自动动画。为了使得一个ViewGroup具备LayoutTransition的功能,需要调用ViewGroup#setLayoutTransition(LayoutTransition)。
3.2 使用案例
- 布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/shadow_activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<Button
android:text="Add View"
android:onClick="onAddViewClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:orientation="vertical"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</LinearLayout>
- 对linearLayout应用LayoutTransition的代码如下:
package com.xiaomi.androidanimationtest;
import androidx.appcompat.app.AppCompatActivity;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private int mCount=1;
private LinearLayout mLinearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLinearLayout=findViewById(R.id.linearLayout);
}
public void onAddViewClick(View view) {
//创建TextView并设置属性
TextView textView = new TextView(this);
textView.setText("newItem:"+mCount++);
ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 130);
params.bottomMargin=10;
textView.setLayoutParams(params);
textView.setBackgroundColor(getResources().getColor(com.google.android.material.R.color.design_default_color_primary));
textView.setTextColor(Color.WHITE);
textView.setGravity(Gravity.CENTER|Gravity.LEFT);
//创建LayoutTransition
LayoutTransition layoutTransition = new LayoutTransition();
//创建动画
ObjectAnimator animator = ObjectAnimator.ofFloat(textView, "translationX", 200, 0);
//设置动画
layoutTransition.setAnimator(LayoutTransition.APPEARING,animator);
//设置动画时常
layoutTransition.setDuration(500);
//ViewGroup添加LayoutTransition
mLinearLayout.setLayoutTransition(layoutTransition);
mLinearLayout.addView(textView);
}
}
四、后记
好久好久好久没有更博客了,因为毕业后工作的原因,实在是没有多余精力写文章,但是不输出又怎么会进步呢?后续我会坚持输出文章(只是频率比较低了。。。),也希望输出的文章能够帮助到博友,一起进步。