一文搞懂Android动画

news2024/12/23 16:31:52

这里写目录标题

  • 前言
  • 一、视图动画
    • 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实现示例

  1. 在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"/>
  1. 给具体的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实现示例

  1. 在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"/>
  1. 给具体的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实现示例

  1. 在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"/>
  1. 给具体的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实现示例

  1. 在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"/>
  1. 给具体的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实现示例

  1. 在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>
  1. 给具体的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实现示例

  1. 在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>
  1. 给具体的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 使用案例

  1. 布局代码如下:
<?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>
  1. 对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);
    }
}

四、后记

好久好久好久没有更博客了,因为毕业后工作的原因,实在是没有多余精力写文章,但是不输出又怎么会进步呢?后续我会坚持输出文章(只是频率比较低了。。。),也希望输出的文章能够帮助到博友,一起进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/600454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux中查看端口被哪个进程占用、进程调用的配置文件、目录等

1.查看被占用的端口的进程&#xff0c;netstat/ss -antulp | grep :端口号 2.通过上面的命令就可以列出&#xff0c;这个端口被哪些应用程序所占用&#xff0c;然后找到对应的进程PID 3.根据PID查询进程。如果想详细查看这个进程&#xff0c;PID具体是哪一个进程&#xff0c;可…

Qt6.5.1+WebRTC学习笔记(八)开发环境搭建(win10+vs2019)

一、准备 1.操作系统win10 64位 2.合理的上网方式&#xff0c;需要正常访问google,最好有20G以上流量 3.安装VS2019&#xff0c;笔者使用的是社区版&#xff0c;并选中C相关&#xff0c;笔者设置如下 注意&#xff0c;win10的sdk需要是10.0.20348.1&#xff0c;其他版本可能…

JavaWeb17(过滤器监听器)

目录 1.过滤器/拦截器-Filter. 1.1过滤器介绍. 1.2过滤器使用步骤. 1.2.1创建过滤器. 1.2.2映射配置. 1.3案例1-编码设置. 1.4案例2-登陆状态验证. 1.4过滤链-略带. 2.监听器-Listener. 2.1监听器介绍. 2.2案例演示1-统计在线人数. 2.3案例演示2-统计历史在线人数.…

太好玩了!用Python做音乐节奏可视化!

大家注意&#xff1a;因为微信最近又改了推送机制&#xff0c;经常有小伙伴说错过了之前被删的文章&#xff0c;比如前阵子冒着风险写的爬虫&#xff0c;再比如一些限时福利&#xff0c;错过了就是错过了。 所以建议大家加个星标&#xff0c;就能第一时间收到推送。&#x1f44…

【Python C扩展】零基础也能轻松掌握的学习路线与参考资料

Python C扩展是将Python语言与C语言相结合&#xff0c;最大限度地利用C语言的高性能和Python语言的灵活性&#xff0c;使Python程序获得更高的运行效率。Python C扩展的学习路线涵盖了C语言基础、Python语言、Python C API等多个方面。下面将详细介绍Python C扩展的学习路线&am…

Python+Yolov5人脸表情特征识别

程序示例精选 PythonYolov5人脸表情特征识别 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<PythonYolov5人脸表情特征识别>>编写代码&#xff0c;代码整洁&#xff0c;规则&am…

【微服务架构】专家组:在过去十年的微服务中,我们学到了什么?

瓦特&#xff08;Watt&#xff09;&#xff1a;这是微服务专家组。Chris早些时候谈到了最小化微服务中的设计时耦合。他是microservices.io的创建者&#xff0c;《微服务模式》一书的作者。他也是Java冠军&#xff0c;在微服务领域非常有经验。我期待着与你们一起深入研究其中的…

区间预测 | MATLAB实现基于QRCNN-BiLSTM-Multihead-Attention卷积神经网络结合双向长短期记忆神经网络多变量时间序列区间预测

区间预测 | MATLAB实现QRCNN-BiLSTM-Multihead-Attention卷积神经网络结合双向长短期记忆神经网络多变量时间序列区间预测 目录 区间预测 | MATLAB实现QRCNN-BiLSTM-Multihead-Attention卷积神经网络结合双向长短期记忆神经网络多变量时间序列区间预测效果一览基本介绍模型描述…

chatgpt赋能python:Python冒泡排序:理解流程图

Python冒泡排序&#xff1a;理解流程图 当涉及到排序算法时&#xff0c;Python中最流行的算法之一就是冒泡排序。它是一种简单而有效的排列方法&#xff0c;旨在让列表中的元素按升序或降序排列。在此文章中&#xff0c;我们将讨论冒泡排序的流程图&#xff0c;并重点介绍每个…

JavaWeb18(文件上传富文本编辑器)

目录 一、富文本编辑器 1.1 什么是富文本编辑器? 1.2 CKEditor 1.3 CKEditor 4的使用步骤【参考官方文档】 1.4 优化商品增加、查看、修改功能 1.5 尝试课外扩展其他富文本编辑器 二、文件上传 2.1 到底客户端的文件是上传到哪里? 2.2 SmartUpload是什么? 2.3 Sma…

聚观早报 |ChatGPT之父称AI可能灭绝人类;Kindle本月关闭电子书店

今日要闻&#xff1a;马斯克到访特斯拉上海超级工厂&#xff1b;ChatGPT之父称AI可能灭绝人类&#xff1b;Kindle本月关闭电子书店&#xff1b;FF91将进入交付阶段&#xff1b;iPhone14最高降1900元 马斯克到访特斯拉上海超级工厂 6 月 1 日消息&#xff0c;据航班APP信息显示…

记录--面试官:“你知道什么情况下 HTTPS 不安全么”

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 面试官&#xff1a;“HTTPS的加密过程你知道么&#xff1f;” 我&#xff1a;“那肯定知道啊。” 面试官&#xff1a;“那你知道什么情况下 HTTPS 不安全么” 我&#xff1a;“这....” 越面觉得自己越…

LEAP模型(能源环境发展、碳排放建模预测及不确定性分析)

在国家“3060”碳达峰碳中和的政策背景下&#xff0c;如何寻求经济-能源-环境的平衡有效发展是国家、省份、城市及园区等不同级别经济体的重要课题。根据国家政策、当地能源结构、能源技术发展水平以及相关碳排放指标制定合理有效的低碳能源发展规划需要以科学准确的能源环境发…

在金融数据里挖呀挖,GaussDB开出了花

北京是首都&#xff0c;上海是魔都&#xff0c;那深圳是什么&#xff1f;如果在网上问这个问题&#xff0c;网友会告诉你&#xff0c;深圳是“搞钱之都”。 金融在深圳扮演着关键角色&#xff0c;金融产业的配套数字化基础设施地位也自然也非常重要。深圳的银行、券商等金融机构…

(2)NUC980 Uboot制作

目录&#xff1a; (1)NUC980 编译环境搭建 (2)NUC980 Uboot制作 (3)NUC 980 kenerl编译 u-boot&#xff1a; &#xff08;1&#xff09;下载u-boot: A:下载连接&#xff1a; 下载地址&#xff1a;https://gitee.com/OpenNuvoton/NUC970_U-Boot_v2016.11 文件&#xff1a;NUC97…

分布式存储ceph

ceph架构&#xff0c;三个默认接口&#xff08;块存储RBD&#xff0c;文件存储cephFS&#xff0c;对象存储RGW&#xff09; LibRADOS对象访问接口 RADOS基础存储系统&#xff08;统一存储池&#xff09; #最底层 ceph架构 osd&#xff0c;负责存储数据&#xff0c;一般一个…

27.hadoop系列之50G数据清洗入库秒查询实践

1. 项目背景 目前本地有50G的企业年报csv数据, 需要清洗出通信地址&#xff0c;并需要与原有的亿条数据合并以供业务查询最新的企业通信地址 2. 技术选型 Hadoop ClickHouse 3. Hadoop数据清洗 我们50G的数据无须上传至集群处理&#xff0c;上传目前带宽2M/S, 巨慢&#x…

【shiro】shiro整合JWT——1.需要创建的类

前言 shiro整合JWT系列&#xff0c;主要记录核心思路–如何在shiroredis整合JWTToken。 该篇主要讲述整合JWT需要创建那些类&#xff0c;如下&#xff1a; JwtToken &#xff08;JWT实体类&#xff09;JwtUtil &#xff08;JWT工具类&#xff09;JwtFilter &#xff08;JWT拦…

IIS日志分析

一、下载IIS日志分析软件 地址如下&#xff1a; 开放网盘: 寄存一些分享出来的文件之类的东西 其中就是LogParser和LPS两个压缩文件 二、安装软件 1、需要先安装Log Parser 运行安装上面的文件。 2. 运行Log Parser Studio 在解压的LPSV2.D1文件夹中运行LPS.exe 出现下面…

BR 4P3040.00-490 标准PLC采用梯形逻辑编程

B&R 4P3040.00-490 奥地利贝加莱 电源面板 可编程逻辑控制器(Programmable Logic Controller)技术通常与梯形逻辑编程隔离通信——这是B&R迈出的一大步。B&R平台是基于PC的&#xff0c;这意味着您可以使用PLC系统中不常见的编程语言和功能。例如&#xff0c;可以用…