相关文章推荐
路过的洋葱  ·  org.openqa.selenium.Ja ...·  1 年前    · 
很酷的柑橘  ·  Asynchronous Requests ...·  1 年前    · 

属性动画系统不但能轻松为视图对象本身添加动画效果,而且提供了对 ViewGroup 布局的更改添加动画效果的功能。

可使用 LayoutTransition 类为 ViewGroup 内的布局更改添加动画效果。当向 ViewGroup 中添加或删除视图时,或者使用 setVisibility() 方法改变视图的可见性( VISIBLE INVISIBLE GONE )时,这些视图会经历出现和消失动画,或者以动画的形式移动到新的位置。

一、使用视图默认布局动画

使用视图默认的布局动画,相对比较简单,只需要在 XML 布局文件中,在需要添加布局动画的 ViewGroup 定义代码中添加 android:animateLayoutChanges="true" 属性配置,属性值为 true 。那么,在这个 ViewGroup 内的视图变更时,就会有系统默认的布局动画了。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:animateLayoutChanges="true">
    <Button
        android:id="@+id/btnShow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="隐藏"/>
    <Button
        android:id="@+id/btnHide"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toRightOf="@+id/btnShow"
        app:layout_constraintTop_toTopOf="parent"
        android:text="隐藏按钮"/>
    <Button
        android:id="@+id/btnAnimator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toRightOf="@+id/btnHide"
        app:layout_constraintTop_toTopOf="parent"
        android:text="加载动画"/>
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minWidth="200dp"
        android:minHeight="200dp"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnShow"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:clickable="true"
        android:stateListAnimator="@animator/selector_animate_scale"/>
</androidx.constraintlayout.widget.ConstraintLayout>
 

注意事项:也可以在代码中使用 ViewGroup.LayoutTransition() 方法启用布局变更动画。

二、使用 LayoutTransition 类为 ViewGroup 添加布局动画

    使用系统默认的布局动画配置简单,但是可能会没有布局动画,也不一定是开发者想要的效果。可以通过获取 ViewGroupLayoutTransition 对象,然后调用 LayoutTransition 对象的 setAnimator() 方法设置相应的动画。可设置的布局动画有四类,用 LayoutTransision 类的常量定义,分别是:

  • APPEARING - 该动画在容器中出现的项上运行。
  • CHANGE_APPEARING - 该动画在因某个新项目在容器中出现而变化的项上运行。
  • DISAPPEARING - 该动画在从容器中消失的项上运行。
  • CHANGE_DISAPPEARING - 该动画在因某个项从容器中消失而变化的项上运行。
  • 示例
  • res/animator/animator_view_appearing.xml : APPEARING 动画
<?xml version="1.0" encoding="utf-8"?>
<!-- 项目出现动画,透明度0 -> 1,X和Y方向缩放从 0 -> 1 -->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300">
    <propertyValuesHolder android:propertyName="alpha" android:valueType="floatType" android:valueFrom="0.0" android:valueTo="1.0" />
    <propertyValuesHolder android:propertyName="scaleX" android:valueType="floatType" android:valueFrom="0.0" android:valueTo="1.0" />
    <propertyValuesHolder android:propertyName="scaleY" android:valueType="floatType" android:valueFrom="0.0" android:valueTo="1.0" />
</objectAnimator>
  • res/animator/animator_view_disappearing.xml : DISAPPEARING 动画
<?xml version="1.0" encoding="utf-8"?>
<!-- 项目消失动画,透明度1 -> 0,X和Y方向缩放从 1 -> 0 -->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300">
    <propertyValuesHolder android:propertyName="alpha" android:valueType="floatType" android:valueFrom="1.0" android:valueTo="0.0" />
    <propertyValuesHolder android:propertyName="scaleX" android:valueType="floatType" android:valueFrom="1.0" android:valueTo="0.0" />
    <propertyValuesHolder android:propertyName="scaleY" android:valueType="floatType" android:valueFrom="1.0" android:valueTo="0.0" />
</objectAnimator>
  • 在代码中为 ViewGroup 设置布局动画
findViewById<ViewGroup>(R.id.container).apply {
    if(null == layoutTransition) {
        layoutTransition = LayoutTransition()
    layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, AnimatorInflater.loadAnimator(this@AnimActivity, R.animator.animator_view_disappearing))
    layoutTransition.setAnimator(LayoutTransition.APPEARING, AnimatorInflater.loadAnimator(this@AnimActivity, R.animator.animator_view_appearing))
 

动画的定义也可以在代码中进行.

注意事项:
1. 修改默认布局变更动画的前提是先启用布局变更动画(请参考:
使用视图默认布局动画);
2. 布局更改动画是分类型设置,没有设置的将以系统默认动画;
3. 布局变更的动画播放时长不能超过系统默认值,超过默认值将以默认值为动画时长;
4. 对于 CHANGE_APPEARING 动画和 CHANGE_DISAPPEARING 动画,请参考:LayoutTransition 详解

三、 LayoutTransition 详解

    LayoutTransition 类是用来为 ViewGroup 对象内的布局发生变更自动添加动画的。前面介绍的两种为 ViewGroup 启用布局变化动画都是同样的原理(XML 布局中配置和代码中配置),就是为 ViewGroup 设置一个 LayoutTransition 对象,设置之后会使用系统默认的动画,开发者也可以指定自定义的动画。

    ViewGroup 布局变更可以概括为两类变更(出现和消失),这些变更伴随着四种变更动画(APPEARINGCHANGE_APPEARINGDISAPPEARINGCHANGE_DISAPPEARING)。在默认情况下,DISAPPEARING 动画和 CHANGE_APPEARING 都会立即开始,另一类动画将会根据动画的默认时间延迟开始。这样一来,就形成了这样一条动画序列:当一个项目添加到布局中时,容器的其他子项目就会先移动(为了腾出空间给新项目),然后新增的项目就会伴随着 APPEARING 动画添加进来。相反地,当一个项目从容器中移除时,该项目会先伴随 DISAPPEARING 动画从容器中移除,然后其他项目就会伴随动画移动(为了填充移除项目产生的间隙) 。如果你不想使用这种默认的编排顺序,可以调用 setDuration(int, long)setStartDelay(int, long) 方法适当地调整某些(或者全部)动画。

特别注意:任何情况下,如果在 DISAPPEARING 动画完成之前就开始 APPEARING 动画, DISAPPEARING 动画就会立即停止,并且恢复 DISAPPEARING 动画产生的所有效果。相反地,如果在 APPEARING 动画完成之前就开始 DISAPPEARING 动画, APPEARING 动画也会立即停止,并且恢复 APPEARING 动画产生的效果。(此处说的是对于一个项目的状态,即中断了当前动画反操作的情况)

    过渡指定的所有动画,包括默认的和用户自定义的,都只是模板。也就是说,这些动画的存在是为了保留基本的动画属性,例如时长、开始延时和添加动画的属性。但是,实际的目标对象以及这些属性的始值和结束值,都会在每次运行过渡时自动设置。每一个动画都是从原始副本中克隆,然后向克隆中填充需要动画对象的动态值(例如:由布局事件而移动的布局容器中的子项)以及变化的值(例如:对象的位置、大小)。推送给动画的实际值取决于动画指定的属性。例如:默认的 CHANGE_APPEARING 动画指定动画属性有 lefttoprightbottomscrollXscrollY。在过度开始时,这些属性的值就会使用布局前和布局后的值进行更新。假如使用已知目标对象和属性名称的 ObjectAnimator 对象自定义动画,这些动画也会以同样的方式填充目标和动画值。

    LayoutTransition 类以及相关的 XML 标记 animateLayoutChanges ="true",为直接情况下的自动变更提供了一个简单实用的工具。由于布局多个层级之间的相互关系,因此无法在多层次嵌套视图上使用 LayoutTransition。另外,在添加或者移除项目时同时滚动的容器,也可能不适用这个工具,因为在动画运行时容器也正在滚动,当动画结束之后,由 LayoutTransition 计算出来的动画前后的位置可能跟实际位置不匹配。你可以在这种特殊情况下通过设置 CHANGE_APPEARINGCHANGE_DISAPPEARING 动画对象为 null 的方法禁用这类变更动画,并且适当的设置其他动画的 startDelay

更多关于 LayoutTransition 相关接口介绍请参考Google 官方文档: LayoutTransition

3.1 关于自定义布局变更动画需要注意的事项

    在 使用 LayoutTransition 类为 ViewGroup 添加布局动画 章节简单介绍了使用 LayoutTransition 自定义布局变更动画,笔者在尝试过程中发现, APPEARINGDISAPPEARING l两个动画跟 CHANGE_APPEARINGCHANGE_DISAPPEARING 这两个动画不一样。前者适用类似缩放、渐变这类属性动画即可,但是后者却不行,必须包含 lefttoprightbottomscrollXscrollY 这些属性,大家在自定义布局变更动画的时候,一定要注意这点,否则设置了无效的动画,会无动画效果。笔者查看了下 LayoutTransition 源码,其定义默认动画的代码是这样的,大家在自定义自己的布局变更动画时可以参考下:

public LayoutTransition() {
    if (defaultChangeIn == null) {
        // "left" is just a placeholder; we'll put real properties/values in when needed
        PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);
        PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
        PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 1);
        PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 1);
        PropertyValuesHolder pvhScrollX = PropertyValuesHolder.ofInt("scrollX", 0, 1);
        PropertyValuesHolder pvhScrollY = PropertyValuesHolder.ofInt("scrollY", 0, 1);
        defaultChangeIn = ObjectAnimator.ofPropertyValuesHolder((Object)null,
            pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScrollX, pvhScrollY);
        defaultChangeIn.setDuration(DEFAULT_DURATION);
        defaultChangeIn.setStartDelay(mChangingAppearingDelay);
        defaultChangeIn.setInterpolator(mChangingAppearingInterpolator);
        defaultChangeOut = defaultChangeIn.clone();
        defaultChangeOut.setStartDelay(mChangingDisappearingDelay);
        defaultChangeOut.setInterpolator(mChangingDisappearingInterpolator);
        defaultChange = defaultChangeIn.clone();
        defaultChange.setStartDelay(mChangingDelay);
        defaultChange.setInterpolator(mChangingInterpolator);
        defaultFadeIn = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
        defaultFadeIn.setDuration(DEFAULT_DURATION);
        defaultFadeIn.setStartDelay(mAppearingDelay);
        defaultFadeIn.setInterpolator(mAppearingInterpolator);
        defaultFadeOut = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
        defaultFadeOut.setDuration(DEFAULT_DURATION);
        defaultFadeOut.setStartDelay(mDisappearingDelay);
        defaultFadeOut.setInterpolator(mDisappearingInterpolator);
    mChangingAppearingAnim = defaultChangeIn;
    mChangingDisappearingAnim = defaultChangeOut;
    mChangingAnim = defaultChange;
    mAppearingAnim = defaultFadeIn;
    mDisappearingAnim = defaultFadeOut;

四、动画效果对界面性能的影响

    所有的效果都是以性能为代价的,用于更新界面的 Animator 会使动画运行的每一帧都进行额外的渲染。因此,使用资源密集型动画可能会对应用的性能产生负面影响,所以开发者要合理使用动画。

上一篇:Android 属性动画(四)使用动画插值器
下一篇:Android 属性动画(六)使用 ViewPropertyAnimator 实现多属性动画效果

&nbsp;&nbsp;&nbsp;&nbsp;属性动画系统不但能轻松为视图对象本身添加动画效果,而且提供了对 ViewGroup 布局的更改添加动画效果的功能。&nbsp;&nbsp;&nbsp;&nbsp;可使用 LayoutTransition 类为ViewGroup 内的布局更改添加动画效果。当向 ViewGroup 中添加或删除视图时,或者使用 setVisibility() 方法改变视图的可见性(VISIBLE、INVISIBLE 或 GONE)时,这些视图会经历出现和消失动画,或者以动画的形 一、布局动画 布局动画的作用于ViewGroup,执行动画效果的是内部的子View布局动画android中可以通过LayoutAnimation或LayoutTransition来实现。 1.LayoutAnimation LayoutAnimation实际上是一... public class MyCustomView extends ViewGroup implements View.OnClickListener { private OnMenuItemClickListener mMenuItemClickListener; * 点击子菜单项的回调接口 public interface OnMenuItemClickListener { void onClick(View view, int pos);     在某些情况下,我们需要为图片添加动画效果,比如在用户操作之后,将图标转换成另一张图标。Android 提供了多张方案为 Drawable 添加动画。首先就是使用 AnimationDrawable ,这种方案通过指定多张静态的 Drawable 图片文件组合在一起构成动画(每个时刻只显示一张图片)。另一种就是使用 AnimatedVectorDrawable,这种方案是通过改变矢量图片的属性实现动画。 二、使用 AnimationDrawable     Android提供了动力学动画(DynamicAnimation)的支持,这类动画带有物理动力学的相关特性(而不是硬生生的变化),其中弹簧动画(SpringAnimation)就是一种。顾名思义,弹簧动画就是符合弹簧收缩特性的动画
一、属性动画简介     Android动画有很多种,属性动画就是其中的一种。所谓的属性动画,就是在指定的时间内,通过改变对象的属性达到变化效果动画。在 Android 中,属性动画系统是一个强健的框架,几乎可以为任何内容添加动画效果。实现属性动画也是通过 Android属性动画系统实现,开发者只需要定义动画的一些属性即可完成,这些属性如下: 时长(duration):指定动画的时长。默认时长为 300 毫秒。 时间插值(interpolator):指定如
    在前面章节中,提到了 使用 AnimatorSet 编排多个动画,通过 AnimatorSet 可以直接为一个目标对象的多个属性添加动画效果。对于实现由多个属性共同组成的动画效果,还有一种更优的方案,那就是 ViewPropertyAnimator。 二、使用 ViewPropertyAnimator 实现多属性动画效果     ViewPropertyAnimator 有助于使用单个底层 Animator 对
要在 Android 中实现显示和隐藏布局动画,可以使用以下方法: 1. 通过布局属性设置动画:在布局文件中设置 `android:animateLayoutChanges="true"` 属性,这样当布局变化时,Android 将自动为您处理动画效果。 2. 使用 ViewPropertyAnimator:使用 ViewPropertyAnimator 可以实现简单的渐变、平移、缩放等动画效果。例如,以下代码可以实现一个简单的渐变动画: // 显示布局 layout.setVisibility(View.VISIBLE); layout.animate().alpha(1.0f); // 隐藏布局 layout.animate().alpha(0.0f).withEndAction(new Runnable() { @Override public void run() { layout.setVisibility(View.GONE); 3. 使用 LayoutTransitionLayoutTransition 可以为视图容器添加动画效果,包括添加、移除、更改视图等操作。例如,以下代码可以实现一个简单的淡入淡出效果: // 创建 LayoutTransition 对象 LayoutTransition transition = new LayoutTransition(); // 设置淡入淡出动画 ObjectAnimator fadein = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f); ObjectAnimator fadeout = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f); transition.setAnimator(LayoutTransition.APPEARING, fadein); transition.setAnimator(LayoutTransition.DISAPPEARING, fadeout); // 将 LayoutTransition 应用到容器 ViewGroup container = findViewById(R.id.container); container.setLayoutTransition(transition); 希望这些方法可以帮助你实现显示和隐藏布局动画