创建自定义过渡动画

尝试 Compose 方式
Jetpack Compose 是推荐的 Android 界面工具包。了解如何在 Compose 中添加动画。

自定义过渡让您可以创建内置过渡类中未提供的动画。例如,您可以定义一个自定义过渡,将文本和输入字段的前景色变为灰色,以指示这些字段在新屏幕中处于禁用状态。此类更改有助于用户看到您禁用的字段。

自定义过渡与内置过渡类型一样,会将动画应用到起始场景和结束场景的子视图。但是,与内置过渡类型不同,您必须提供捕获属性值并生成动画的代码。您可能还需要为动画定义目标视图的子集。

本页介绍如何捕获属性值并生成动画以创建自定义过渡。

扩展 Transition 类

要创建自定义过渡,请在项目中添加一个扩展 Transition 类的类,并替换以下代码段中所示的函数

Kotlin

class CustomTransition : Transition() {

    override fun captureStartValues(transitionValues: TransitionValues) {}

    override fun captureEndValues(transitionValues: TransitionValues) {}

    override fun createAnimator(
        sceneRoot: ViewGroup,
        startValues: TransitionValues?,
        endValues: TransitionValues?
    ): Animator? {}

}

Java

public class CustomTransition extends Transition {

    @Override
    public void captureStartValues(TransitionValues values) {}

    @Override
    public void captureEndValues(TransitionValues values) {}

    @Override
    public Animator createAnimator(ViewGroup sceneRoot,
                                   TransitionValues startValues,
                                   TransitionValues endValues) {}
}

以下部分说明如何替换这些函数。

捕获视图属性值

过渡动画使用属性动画概览中描述的属性动画系统。属性动画会在指定的时间段内将视图属性从起始值更改为结束值,因此框架需要属性的起始值和结束值来构建动画。

但是,属性动画通常只需要视图所有属性值的一小部分。例如,颜色动画需要颜色属性值,而运动动画需要位置属性值。由于动画所需的属性值特定于过渡,因此过渡框架不会向过渡提供每个属性值。相反,框架会调用回调函数,允许过渡仅捕获其需要的属性值并将其存储在框架中。

捕获起始值

要将起始视图值传递给框架,请实现 captureStartValues(transitionValues) 函数。框架会为起始场景中的每个视图调用此函数。函数参数是一个 TransitionValues 对象,其中包含对视图的引用和 Map 实例,您可以在其中存储您想要的视图值。在您的实现中,检索这些属性值并通过将它们存储在 map 中,将其传回框架。

为了确保属性值的键与其他 TransitionValues 键不冲突,请使用以下命名方案

package_name:transition_name:property_name

以下代码段显示了 captureStartValues() 函数的实现

Kotlin

class CustomTransition : Transition() {

    // Define a key for storing a property value in
    // TransitionValues.values with the syntax
    // package_name:transition_class:property_name to avoid collisions
    private val PROPNAME_BACKGROUND = "com.example.android.customtransition:CustomTransition:background"

    override fun captureStartValues(transitionValues: TransitionValues) {
        // Call the convenience method captureValues
        captureValues(transitionValues)
    }

    // For the view in transitionValues.view, get the values you
    // want and put them in transitionValues.values
    private fun captureValues(transitionValues: TransitionValues) {
        // Get a reference to the view
        val view = transitionValues.view
        // Store its background property in the values map
        transitionValues.values[PROPNAME_BACKGROUND] = view.background
    }

    ...

}

Java

public class CustomTransition extends Transition {

    // Define a key for storing a property value in
    // TransitionValues.values with the syntax
    // package_name:transition_class:property_name to avoid collisions
    private static final String PROPNAME_BACKGROUND =
            "com.example.android.customtransition:CustomTransition:background";

    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        // Call the convenience method captureValues
        captureValues(transitionValues);
    }


    // For the view in transitionValues.view, get the values you
    // want and put them in transitionValues.values
    private void captureValues(TransitionValues transitionValues) {
        // Get a reference to the view
        View view = transitionValues.view;
        // Store its background property in the values map
        transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground());
    }
    ...
}

捕获结束值

框架会为结束场景中的每个目标视图调用 captureEndValues(TransitionValues) 函数一次。在所有其他方面,captureEndValues() 的工作方式与 captureStartValues() 相同。

以下代码段显示了 captureEndValues() 函数的实现

Kotlin

override fun captureEndValues(transitionValues: TransitionValues) {
    captureValues(transitionValues)
}

Java

@Override
public void captureEndValues(TransitionValues transitionValues) {
    captureValues(transitionValues);
}

在此示例中,captureStartValues()captureEndValues() 函数都调用 captureValues() 来检索和存储值。captureValues() 检索的视图属性是相同的,但其在起始场景和结束场景中的值不同。框架会为视图的起始状态和结束状态维护单独的 map。

创建自定义动画器

要为视图从起始场景中的状态到结束场景中的状态的变化添加动画,请通过替换 createAnimator() 函数来提供动画器。当框架调用此函数时,它会传递场景根视图以及包含您捕获的起始值和结束值的 TransitionValues 对象。

框架调用 createAnimator() 函数的次数取决于起始场景和结束场景之间发生的变化。

例如,考虑作为自定义过渡实现的淡出或淡入动画。如果起始场景有五个目标,其中两个从结束场景中移除,而结束场景包含起始场景中的三个目标和一个新目标,则框架会调用 createAnimator() 六次。其中三次调用会为同时存在于两个场景对象中的目标的淡出和淡入添加动画。另外两次调用会为从结束场景中移除的目标的淡出添加动画。一次调用会为结束场景中的新目标的淡入添加动画。

对于同时存在于起始场景和结束场景中的目标视图,框架会为 startValuesendValues 参数提供一个 TransitionValues 对象。对于仅存在于起始场景或结束场景中的目标视图,框架会为对应的参数提供 TransitionValues 对象,而为另一个参数提供 null

创建自定义过渡时,要实现 createAnimator(ViewGroup, TransitionValues, TransitionValues) 函数,请使用您捕获的视图属性值创建 Animator 对象,并将其返回给框架。有关示例实现,请参阅 CustomTransition 示例中的 ChangeColor 类。有关属性动画器的更多信息,请参阅属性动画

应用自定义过渡

自定义过渡的工作方式与内置过渡相同。您可以使用过渡管理器应用自定义过渡,如应用过渡中所述。