原則: ValueAnimator 属性アニメーション クラスを使用して実装します。これにより、値の変更を通じてオブジェクトの属性値が手動で設定され、アニメーション効果が実現されます。コードを直接貼り付けます。
public static void doNumberAnim(TextView tvPrice, float startNumber, float endNumber) {
ValueAnimator animator = ValueAnimator.ofFloat(startNumber, endNumber);
animator.setDuration(800);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
tvPrice.setText(animation.getAnimatedValue().toString());
}
});
animator.start();
}
公式サイトでは次のように説明されています。
このクラスは、アニメーション値を計算してターゲット オブジェクトに設定するアニメーションを実行するための単純なタイミング エンジンを提供します。
すべてのアニメーションで使用される単一のタイミング パルスがあります。これはカスタム ハンドラーで実行され、プロパティの変更が UI スレッドで確実に行われるようにします。
デフォルトでは、ValueAnimator はクラスを介して非線形時間補間を使用し、
AccelerateDecelerateInterpolator
アニメーションへの加速とアニメーションからの減速を行います。この動作は、 を呼び出すことで変更できますsetInterpolator
。アニメーターは、コード ファイルまたはリソース ファイルから作成できます。ValueAnimator リソース ファイルの例を次に示します。
ValueAnimator は、マルチステップ アニメーションを作成するための
PropertyValuesHolder
と リソース タグの組み合わせの使用もサポートしています 。Keyframe
各キーフレームに明示的な小数値 (0 から 1) を指定して、全体の継続時間内でアニメーションがいつその値に到達するかを決定できることに注意してください。あるいは、小数部分を省略したままにすることもでき、キーフレームは合計期間内で均等に分配されます。
このクラスは、アニメーション値を計算してターゲット オブジェクトに設定するアニメーションを実行するためのシンプルなタイミング エンジンを提供します。すべてのアニメーションは単一のタイミング パルスを使用します。これはカスタム ハンドラーで実行され、プロパティの変更が UI スレッドで確実に行われるようにします。
デフォルトでは、ValueAnimator はクラスを通じて非線形時間補間を使用します。これにより、アニメーションまで加速し、アニメーションから減速します。この動作は呼び出しによって変更できます。AccelerateDecelerateInterpolatorsetInterpolator
アニメーターはコードまたはリソース ファイルから作成できます。ValueAnimator リソース ファイルの例を次に示します。
ValueAnimator は、 と リソース タグの組み合わせを使用したマルチステップ アニメーションの作成もサポートしています。各キーフレームに明示的な 10 進値 (0 から 1) を指定して、アニメーションが継続時間全体にわたっていつその値に到達するかを決定できることに注意してください。あるいは、分数をオフにすると、キーフレームが合計期間にわたって均等に分散されます: PropertyValuesHolderKeyframe
要約する
絶え間ない |
|
---|---|
static final int |
INFINITE = -1
この値は、アニメーションを無期限に繰り返すプロパティとともに使用されます。 |
static final int |
RESTART = 1
アニメーションが最後に達し、INFINITE または正の値になると、アニメーションは最初から再開されます。 |
static final int |
REVERSE = 2
アニメーションが最後に達し、無限または正の値になると、アニメーションは反復ごとに方向を反転します。 |
パブリックコンストラクター |
---|
新しい ValueAnimator オブジェクトを作成します。 |
パブリックメソッド |
|
---|---|
static boolean |
システム全体のアニメーターが現在有効かどうかを返します。 |
void |
cancel()
アニメーションをキャンセルします。 |
@NonNull ValueAnimator |
clone()
|
void |
end()
アニメーションを終了します。 |
float |
現在のアニメーション スコアを返します。これは、アニメーションの最新のフレーム更新で使用される経過/補間スコアです。 |
@NonNull Object |
1 つのプロパティのみがアニメーション化される場合に、これから計算される最新の値。 |
@Nullable Object |
getAnimatedValue(@NonNull String propertyName)
これから計算される最新の値は です。 |
long |
時間内のアニメーションの現在位置を取得します。これは、現在時刻からアニメーションが開始された時刻を引いたものと等しくなります。 |
long |
アニメーションの長さを取得します。 |
static long |
アニメーションの各フレーム間の時間 (ミリ秒単位)。 |
@Nullable Interpolator |
この値アニメータによって使用されるタイミング補間器を返します。 |
@NonNull String |
デバッグ目的でこのアニメーターの名前を返します。 |
int |
アニメーションを繰り返す回数を定義します。 |
int |
このアニメーションが最後に達したときに何をすべきかを定義します。 |
long |
遅延開始アニメーションを呼び出す時間 (ミリ秒単位)。 |
long |
アニメーション シーケンス、開始遅延、繰り返しを含むアニメーションの合計時間を取得します。 |
@NonNull PropertyValuesHolder[] |
この値アニメーターがアニメーション化する間の値を返します。 |
boolean |
このアニメーターが現在実行中かどうか (開始され、初期起動遅延期間を超えており、まだ終了していない) かどうかを返します。 |
boolean |
このアニメーターが開始され、まだ終了していないかどうかを返します。 |
static @NonNull ValueAnimator |
カラー値間でアニメーション化する ValueAnimator を構築して返します。 |
static @NonNull ValueAnimator |
浮動小数点値間をアニメーション化する ValueAnimator を構築して返します。 |
static @NonNull ValueAnimator |
int 値間でアニメーション化する ValueAnimator を構築して返します。 |
static @NonNull ValueAnimator |
ofObject(@NonNull TypeEvaluator evaluator, @NonNull Object[] values)
オブジェクト値間をアニメーション化する ValueAnimator を構築して返します。 |
static @NonNull ValueAnimator |
ofPropertyValuesHolder(@NonNull PropertyValuesHolder[] values)
PropertyValuesHolder オブジェクトで指定された値の間でアニメーション化する ValueAnimator を構築して返します。 |
void |
pause()
実行中のアニメーションを一時停止します。 |
void |
resume()
一時停止したアニメーションを再開し、アニメータが一時停止したときに中断したところから続行できるようにします。 |
void |
reverse()
ValueAnimator を逆再生します。 |
void |
setCurrentFraction(float fraction)
アニメーションの位置を指定された部分に設定します。 |
void |
setCurrentPlayTime(long playTime)
アニメーションの位置を指定された時点に設定します。 |
@NonNull ValueAnimator |
setDuration(long duration)
アニメーションの長さを設定します。 |
void |
setEvaluator(@NonNull TypeEvaluator value)
このアニメーションのアニメーション値を計算するときに使用するタイプ エバリュエーター。 |
void |
setFloatValues(@NonNull float[] values)
設定は浮動小数点値の間でアニメーション化されます。 |
static void |
setFrameDelay(long frameDelay)
アニメーションの各フレーム間の時間 (ミリ秒単位)。 |
void |
setIntValues(@NonNull int[] values)
アニメーション化される int 値を設定します。 |
void |
setInterpolator(@Nullable Interpolator value)
このアニメーションの計算に使用される分数補間器。 |
void |
setNameForTrace(@NonNull String animationName)
システム トレースに表示されるアニメーションの名前を設定します。 |
void |
setObjectValues(@NonNull Object[] values)
このアニメーションをアニメーション化する値を設定します。 |
void |
setRepeatCount(int value)
アニメーションを繰り返す回数を設定します。 |
void |
setRepeatMode(@ValueAnimator.RepeatMode int value)
このアニメーションが最後に達したときに何をすべきかを定義します。 |
void |
setStartDelay(long startDelay)
遅延開始アニメーションを呼び出す時間 (ミリ秒単位)。 |
void |
设置每个属性之间的值。 |
void |
start()
启动此动画。 |
@NonNull String |
toString()
|
继承的常量 |
---|
来自androidx.core.animation.Animator |
继承的方法 |
---|
来自androidx.core.animation.Animator |
常数
公共方法
areAnimatorsEnabled
public static boolean areAnimatorsEnabled()
返回系统范围的动画器当前是否已启用。默认情况下,所有动画器都处于启用状态。如果用户将开发人员选项设置为将动画器持续时间比例设置为 0,或者启用电池保存模式(禁用所有动画),则这可能会更改。
开发人员通常不需要调用此方法,但如果应用希望在禁用动画器时显示不同的体验,则可以将此返回值用作要提供的体验的决策程序。
返回 | |
---|---|
boolean |
布尔值 当前是否启用动画器。默认值为 。 |
取消
public void cancel()
取消动画。与 不同,会导致动画停止在其轨道上,向其侦听器发送 ,然后发送消息。end
cancel()
onAnimationCancel
onAnimationEnd
必须在运行动画的线程上调用此方法。
getAnimatedFraction
public float getAnimatedFraction()
返回当前动画分数,这是动画上最近帧更新中使用的经过/插值分数。
返回 | |
---|---|
float |
动画的经过/插值部分。 |
getAnimatedValue
public @NonNull Object getAnimatedValue()
当只有一个属性被动画化时,由此计算的最新值。此值仅在动画运行时是合理的。此只读属性的主要用途是在计算值后立即从调用 期间检索值,该值在每个动画帧期间调用。ValueAnimator
ValueAnimator
onAnimationUpdate
getAnimatedValue
public @Nullable Object getAnimatedValue(@NonNull String propertyName)
由此计算的最新值为 。此只读属性的主要用途是在计算值后立即从调用 期间检索值,该值在每个动画帧期间调用。ValueAnimator
propertyName
ValueAnimator
onAnimationUpdate
getCurrentPlayTime
public long getCurrentPlayTime()
获取动画在时间中的当前位置,该位置等于当前时间减去动画开始的时间。尚未启动的动画将返回零值,除非动画已通过 或 设置了播放时间,在这种情况下,它将返回设置的时间。setCurrentPlayTime
setCurrentFraction
返回 | |
---|---|
long |
动画时间中的当前位置。 |
getDuration
获取动画的长度。默认持续时间为 300 毫秒。
返回 | |
---|---|
long |
动画的长度(以毫秒为单位)。 |
getFrameDelay
public static long getFrameDelay()
动画的每一帧之间的时间量(以毫秒为单位)。这是动画将尝试遵守的请求时间,但帧之间的实际延迟可能会有所不同,具体取决于系统负载和功能。这是一个静态函数,因为相同的延迟将应用于所有动画,因为它们都是从单个计时循环运行的。当动画系统使用外部计时源(如显示刷新率 (vsync))来控制动画时,可以忽略帧延迟。请注意,应从调用的同一线程调用此方法,以便检查该动画的帧延迟。如果调用线程没有 Looper,则会引发运行时异常。start
返回 | |
---|---|
long |
帧之间的请求时间(以毫秒为单位) |
getInterpolator
public @Nullable Interpolator getInterpolator()
返回此值动画器使用的计时插值器。
返回 | |
---|---|
@Nullable Interpolator |
此值动画器的计时插值器。 |
getRepeatCount
<span style="color:var(--devsite-code-color)">public int <a data-cke-saved-href="https://developer.android.google.cn/reference/androidx/core/animation/ValueAnimator#getRepeatCount()" href="https://developer.android.google.cn/reference/androidx/core/animation/ValueAnimator#getRepeatCount()">getRepeatCount</a>()</span>
定义动画应重复的次数。默认值为 0。
返回 | |
---|---|
int |
动画应重复的次数,或 |
getTotalDuration
public long getTotalDuration()
获取动画的总持续时间,包括动画序列、开始延迟和重复。
当动画无限重复时,或者当任何子动画师重复时(通过 } 到 ),总持续时间将为 。否则,总持续时间是开始延迟和动画运行时间的总和(即一次迭代的持续时间乘以迭代次数)。setRepeatCount
INFINITE
DURATION_INFINITE
返回 | |
---|---|
long |
动画完成所需的总时间(从调用的时间开始)。 如果动画或任何子动画无限重复,将返回。 |
getValues
public @NonNull PropertyValuesHolder[] getValues()
返回此值动画器在其间进行动画处理的值。这些值存储在 PropertyValuesHolder 对象中,即使 ValueAnimator 是使用简单的值对象列表创建的。
返回 | |
---|---|
@NonNull PropertyValuesHolder[] |
PropertyValuesHolder[] 一个 PropertyValuesHolder 对象的数组,这些对象保存定义动画的每个属性的值。 |
isStarted
public boolean isStarted()
返回此动画器是否已启动和尚未结束。对于可重用的动画师(除了 生成的单次动画师之外,大多数动画师都是),此状态是 的超集,因为非零的动画师将在延迟阶段返回 true,而只有在延迟阶段完成后才会返回 true。不可重用的动画器在启动后将始终返回 true,因为它们无法返回到非启动状态。createCircularReveal()
isRunning
startDelay
isStarted
isRunning
返回 | |
---|---|
boolean |
动画器是否已启动和尚未结束。 |
ofArgb
public static @NonNull ValueAnimator ofArgb(@NonNull int[] values)
构造并返回一个在颜色值之间进行动画处理的 ValueAnimator。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。
参数 | |
---|---|
@NonNull int[] values |
动画将随时间推移在其之间设置动画效果的一组值。 |
返回 | |
---|---|
@NonNull ValueAnimator |
一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。 |
浮点数
public static @NonNull ValueAnimator ofFloat(@NonNull float[] values)
构造并返回一个在浮点值之间进行动画处理的 ValueAnimator。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。
参数 | |
---|---|
@NonNull float[] values |
动画将随时间推移在其之间设置动画效果的一组值。 |
返回 | |
---|---|
@NonNull ValueAnimator |
一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。 |
ofInt
public static @NonNull ValueAnimator ofInt(@NonNull int[] values)
构造并返回一个在 int 值之间进行动画处理的 ValueAnimator。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。
参数 | |
---|---|
@NonNull int[] values |
动画将随时间推移在其之间设置动画效果的一组值。 |
返回 | |
---|---|
@NonNull ValueAnimator |
一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。 |
对象
public static @NonNull ValueAnimator ofObject(@NonNull TypeEvaluator evaluator, @NonNull Object[] values)
构造并返回一个在对象值之间进行动画处理的 ValueAnimator。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。
注意:Object 值存储为对原始对象的引用,这意味着调用此方法后对这些对象的更改将影响动画器上的值。如果在调用此方法后对象将在外部发生突变,则调用方应改为传递这些对象的副本。
由于 ValueAnimator 不知道如何在任意对象之间进行动画处理,因此此工厂方法还采用 TypeEvaluator 对象,ValueAnimator 将使用该对象来执行该插值。
参数 | |
---|---|
@NonNull TypeEvaluator evaluator |
将在每个动画帧上调用的类型计算器,以在对象值之间提供必要的插值以派生动画值。 |
@NonNull Object[] values |
动画将随时间推移在其之间设置动画效果的一组值。 |
返回 | |
---|---|
@NonNull ValueAnimator |
一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。 |
OfPropertyValuesHolder
public static @NonNull ValueAnimator ofPropertyValuesHolder(@NonNull PropertyValuesHolder[] values)
构造并返回一个 ValueAnimator,该动画器在 PropertyValuesHolder 对象中指定的值之间进行动画处理。
参数 | |
---|---|
@NonNull PropertyValuesHolder[] values |
一组 PropertyValuesHolder 对象,其值将随时间推移进行动画处理。 |
返回 | |
---|---|
@NonNull ValueAnimator |
一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。 |
反向
public void setCurrentFraction(float fraction)
反向播放 ValueAnimator。如果动画已在运行,它将自行停止并从调用 reverse 时达到的点向后播放。如果动画当前未运行,则它将从末尾开始并向后播放。此行为仅针对当前动画设置;动画的未来播放将使用向前播放的默认行为。
设置电流分数
public void setCurrentFraction(float fraction)
将动画的位置设置为指定的分数。此分数应介于 0 和动画的总分数之间,包括任何重复。也就是说,分数 0 会将动画定位在重复一次的反转动画器的开头,值 1 定位在末尾,值 2 定位在末尾。如果动画尚未启动,则在设置为此分数后,它将不会向前前进;它只需将分数设置为此值,并根据该分数执行任何适当的操作。如果动画已经在运行,则 setCurrentFraction() 会将当前分数设置为此值,并从该点继续播放。 由于更改分数,不会调用事件;这些事件仅在动画运行时处理。androidx.core.animation.Animator.AnimatorListener
参数 | |
---|---|
float fraction |
动画前进或倒带到的分数。动画师的最大分数范围之外的值将被钳制到正确的范围。 |
设置当前播放时间
public void setCurrentPlayTime(long playTime)
将动画的位置设置为指定的时间点。此时间应介于 0 和动画的总持续时间(包括任何重复)之间。如果动画尚未启动,则设置为此时后将不再前进;它只会将时间设置为此值,并根据该时间执行任何适当的操作。如果动画已在运行,则 setCurrentPlayTime() 会将当前播放时间设置为此值,并从该点继续播放。
参数 | |
---|---|
long playTime |
动画前进或倒带的时间(以毫秒为单位)。 |
设置持续时间
public @NonNull ValueAnimator setDuration(long duration)
设置动画的长度。默认持续时间为 300 毫秒。
参数 | |
---|---|
long duration |
动画的长度(以毫秒为单位)。此值不能为负数。 |
返回 | |
---|---|
@NonNull ValueAnimator |
ValueAnimator 使用 setDuration() 调用的对象。通过此返回值,可以更轻松地将构造语句组合在一起,然后设置持续时间,如 中所示。 |
setEvaluator
public void setEvaluator(@NonNull TypeEvaluator value)
计算此动画的动画值时要使用的类型赋值器。系统将根据构造函数中的类型和自动分配浮点数或整数赋值器。但是,如果这些值不是这些基元类型之一,或者需要不同的计算(例如表示颜色的 int 值所必需的),则需要分配自定义计算器。例如,在对颜色值运行动画时,应使用 来获取正确的 RGB 颜色插值。startValue
endValue
ArgbEvaluator
如果此值动画器之间只有一组值进行动画处理,则此赋值器将用于该集。如果有几组值正在进行动画处理,例如在 ValueAnimator 上设置了 PropertyValuesHolder 对象,则赋值器仅分配给第一个 PropertyValuesHolder 对象。
参数 | |
---|---|
@NonNull TypeEvaluator value |
此动画要使用的赋值器 |
设置浮点值
public void setFloatValues(@NonNull float[] values)
设置将在浮点值之间进行动画处理。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。
如果已经通过多个 PropertyValuesHolder 对象为此 ValueAnimator 定义了多组值,则此方法将为其中第一个对象设置值。
参数 | |
---|---|
@NonNull float[] values |
动画将随时间推移在其之间设置动画效果的一组值。 |
设置帧延迟
public static void setFrameDelay(long frameDelay)
动画的每一帧之间的时间量(以毫秒为单位)。这是动画将尝试遵守的请求时间,但帧之间的实际延迟可能会有所不同,具体取决于系统负载和功能。这是一个静态函数,因为相同的延迟将应用于所有动画,因为它们都是从单个计时循环运行的。当动画系统使用外部计时源(如显示刷新率 (vsync))来控制动画时,可以忽略帧延迟。请注意,应从调用的同一线程调用此方法,以使新的帧延迟对该动画生效。如果调用线程没有 Looper,则会引发运行时异常。start
参数 | |
---|---|
long frameDelay |
帧之间的请求时间(以毫秒为单位) |
设置整数值
public void setIntValues(@NonNull int[] values)
设置将在两者之间进行动画处理的 int 值。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。
如果已经通过多个 PropertyValuesHolder 对象为此 ValueAnimator 定义了多组值,则此方法将为其中第一个对象设置值。
参数 | |
---|---|
@NonNull int[] values |
动画将随时间推移在其之间设置动画效果的一组值。 |
设置插值器
public void setInterpolator(@Nullable Interpolator value)
用于计算此动画的经过分数的插值器。插值器确定动画是以线性运动还是非线性运动(如加速和减速)运行。默认值为AccelerateDecelerateInterpolator
参数 | |
---|---|
@Nullable Interpolator value |
此动画要使用的插值器。值 将导致线性插值。 |
设置名称跟踪
public void setNameForTrace(@NonNull String animationName)
设置要在系统跟踪中显示的动画的名称。这使特定动画在系统跟踪中可识别。
设置对象值
public void setObjectValues(@NonNull Object[] values)
设置要对此动画进行动画处理的值。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。
注意:Object 值存储为对原始对象的引用,这意味着调用此方法后对这些对象的更改将影响动画器上的值。如果在调用此方法后对象将在外部发生突变,则调用方应改为传递这些对象的副本。
如果已经通过多个 PropertyValuesHolder 对象为此 ValueAnimator 定义了多组值,则此方法将为其中第一个对象设置值。
在 ValueAnimator 上应该设置一个 TypeEvaluator,它知道如何在这些值对象之间进行插值。ValueAnimator 只知道如何在其他 setValues() 方法中指定的基元类型之间进行插值。
参数 | |
---|---|
@NonNull Object[] values |
要在其间进行动画处理的值集。 |
setRepeatCount
public void setRepeatCount(int value)
设置动画应重复的次数。如果重复计数为 0,则永远不会重复动画。如果重复计数大于 0 或 ,则将考虑重复模式。默认情况下,重复计数为 0。INFINITE
参数 | |
---|---|
int value |
动画应重复的次数 |
设置重复模式
public void setRepeatMode(@ValueAnimator.RepeatMode int value)
定义此动画到达末尾时应执行的操作。仅当重复计数大于 0 或 时,才应用此设置。默认值为 。INFINITE
RESTART
参数 | |
---|---|
@ValueAnimator.RepeatMode int value |
设置启动延迟
public void setStartDelay(long startDelay)
调用延迟启动动画的时间量(以毫秒为单位)。请注意,启动延迟应始终为非负数。任何负启动延迟都将在 N 及以上时被钳制为 0。start
参数 | |
---|---|
long startDelay |
延迟量(以毫秒为单位) |
设置值
public void setValues(@NonNull PropertyValuesHolder[] values)
设置每个属性之间的值。此函数由采用值列表的 ValueAnimator 的构造函数在内部调用。但是,可以在没有值的情况下构造 ValueAnimator,并且可以调用此方法来手动设置值。
参数 | |
---|---|
@NonNull PropertyValuesHolder[] values |
每个属性之间的值集。 |
开始
public void start()
启动此动画。如果动画具有非零 startDelay,则动画将在该延迟过后开始运行。非延迟动画将立即设置其初始值,然后调用此动画器的任何侦听器。onAnimationStart
通过调用此方法启动的动画将在调用此方法的线程上运行。此线程上应该有一个 Looper(如果不是这种情况,将引发运行时异常)。此外,如果动画将对视图层次结构中对象的属性进行动画处理,则调用线程应该是该视图层次结构的 UI 线程。