- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
951 lines
32 KiB
Python
951 lines
32 KiB
Python
"""
|
|
Android animation 组件 — Animator, ValueAnimator, ObjectAnimator, 插值器等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
import threading
|
|
import time as _time
|
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypeVar
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
from ..java.lang import RuntimeException
|
|
|
|
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TypeEvaluator
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TypeEvaluator(Stub):
|
|
"""TypeEvaluator — 类型估值器接口"""
|
|
|
|
def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> Any:
|
|
return startValue
|
|
|
|
|
|
class FloatEvaluator(TypeEvaluator):
|
|
"""FloatEvaluator — 浮点估值器"""
|
|
|
|
def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> float:
|
|
sv = float(startValue)
|
|
ev = float(endValue)
|
|
return sv + fraction * (ev - sv)
|
|
|
|
|
|
class IntEvaluator(TypeEvaluator):
|
|
"""IntEvaluator — 整数估值器"""
|
|
|
|
def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> int:
|
|
sv = int(startValue)
|
|
ev = int(endValue)
|
|
return int(sv + fraction * (ev - sv))
|
|
|
|
|
|
class PointFEvaluator(TypeEvaluator):
|
|
"""PointFEvaluator — PointF 估值器"""
|
|
|
|
def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> Any:
|
|
if hasattr(startValue, 'x') and hasattr(startValue, 'y'):
|
|
sv_x, sv_y = startValue.x, startValue.y
|
|
ev_x, ev_y = endValue.x, endValue.y
|
|
class PointF:
|
|
def __init__(self, x, y):
|
|
self.x = x
|
|
self.y = y
|
|
return PointF(sv_x + fraction * (ev_x - sv_x),
|
|
sv_y + fraction * (ev_y - sv_y))
|
|
return startValue
|
|
|
|
|
|
class RectEvaluator(TypeEvaluator):
|
|
"""RectEvaluator — Rect 估值器"""
|
|
|
|
def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> Any:
|
|
if hasattr(startValue, 'left') and hasattr(startValue, 'top'):
|
|
class Rect:
|
|
def __init__(self, l, t, r, b):
|
|
self.left = l
|
|
self.top = t
|
|
self.right = r
|
|
self.bottom = b
|
|
return Rect(
|
|
int(startValue.left + fraction * (endValue.left - startValue.left)),
|
|
int(startValue.top + fraction * (endValue.top - startValue.top)),
|
|
int(startValue.right + fraction * (endValue.right - startValue.right)),
|
|
int(startValue.bottom + fraction * (endValue.bottom - startValue.bottom)),
|
|
)
|
|
return startValue
|
|
|
|
|
|
class ArgbEvaluator(TypeEvaluator):
|
|
"""ArgbEvaluator — ARGB 颜色估值器"""
|
|
|
|
def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> int:
|
|
sv = int(startValue)
|
|
ev = int(endValue)
|
|
a = ((sv >> 24) & 0xFF) + int(fraction * (((ev >> 24) & 0xFF) - ((sv >> 24) & 0xFF)))
|
|
r = ((sv >> 16) & 0xFF) + int(fraction * (((ev >> 16) & 0xFF) - ((sv >> 16) & 0xFF)))
|
|
g = ((sv >> 8) & 0xFF) + int(fraction * (((ev >> 8) & 0xFF) - ((sv >> 8) & 0xFF)))
|
|
b = (sv & 0xFF) + int(fraction * ((ev & 0xFF) - (sv & 0xFF)))
|
|
return (min(a, 255) << 24) | (min(r, 255) << 16) | (min(g, 255) << 8) | min(b, 255)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TimeInterpolator
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TimeInterpolator(Stub):
|
|
"""TimeInterpolator — 时间插值器接口"""
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
return input_
|
|
|
|
|
|
class AccelerateDecelerateInterpolator(TimeInterpolator):
|
|
"""AccelerateDecelerateInterpolator — 加速减速插值器"""
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
return (math.cos((input_ + 1) * math.pi) / 2.0) + 0.5
|
|
|
|
|
|
class AccelerateInterpolator(TimeInterpolator):
|
|
"""AccelerateInterpolator — 加速插值器"""
|
|
|
|
def __init__(self, factor: float = 1.0):
|
|
super().__init__()
|
|
self._factor = factor
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
if self._factor == 1.0:
|
|
return input_ * input_
|
|
return input_ ** (2.0 * self._factor)
|
|
|
|
|
|
class DecelerateInterpolator(TimeInterpolator):
|
|
"""DecelerateInterpolator — 减速插值器"""
|
|
|
|
def __init__(self, factor: float = 1.0):
|
|
super().__init__()
|
|
self._factor = factor
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
if self._factor == 1.0:
|
|
return 1.0 - (1.0 - input_) * (1.0 - input_)
|
|
return 1.0 - (1.0 - input_) ** (2.0 * self._factor)
|
|
|
|
|
|
class LinearInterpolator(TimeInterpolator):
|
|
"""LinearInterpolator — 线性插值器"""
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
return input_
|
|
|
|
|
|
class BounceInterpolator(TimeInterpolator):
|
|
"""BounceInterpolator — 弹跳插值器"""
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
t = input_
|
|
if t < 0.363636:
|
|
return 7.5625 * t * t
|
|
elif t < 0.727272:
|
|
t -= 0.545454
|
|
return 7.5625 * t * t + 0.75
|
|
elif t < 0.909090:
|
|
t -= 0.818181
|
|
return 7.5625 * t * t + 0.9375
|
|
else:
|
|
t -= 0.954545
|
|
return 7.5625 * t * t + 0.984375
|
|
|
|
|
|
class AnticipateInterpolator(TimeInterpolator):
|
|
"""AnticipateInterpolator — 预期插值器"""
|
|
|
|
def __init__(self, tension: float = 2.0):
|
|
super().__init__()
|
|
self._tension = tension
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
return input_ * input_ * ((self._tension + 1) * input_ - self._tension)
|
|
|
|
|
|
class OvershootInterpolator(TimeInterpolator):
|
|
"""OvershootInterpolator — 过冲插值器"""
|
|
|
|
def __init__(self, tension: float = 2.0):
|
|
super().__init__()
|
|
self._tension = tension
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
t = input_ - 1.0
|
|
return t * t * ((self._tension + 1) * t + self._tension) + 1.0
|
|
|
|
|
|
class AnticipateOvershootInterpolator(TimeInterpolator):
|
|
"""AnticipateOvershootInterpolator — 预期过冲插值器"""
|
|
|
|
def __init__(self, tension: float = 2.0, extraTension: float = 1.5):
|
|
super().__init__()
|
|
self._tension = tension
|
|
self._extra_tension = extraTension
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
if input_ < 0.5:
|
|
t = input_ * 2.0
|
|
return 0.5 * t * t * ((self._tension + 1) * t - self._tension)
|
|
else:
|
|
t = (input_ - 0.5) * 2.0 - 1.0
|
|
return 0.5 * (t * t * ((self._tension + 1) * t + self._tension) + 2.0)
|
|
|
|
|
|
class CycleInterpolator(TimeInterpolator):
|
|
"""CycleInterpolator — 周期插值器"""
|
|
|
|
def __init__(self, cycles: float = 1.0):
|
|
super().__init__()
|
|
self._cycles = cycles
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
return math.sin(2 * math.pi * self._cycles * input_)
|
|
|
|
|
|
class PathInterpolator(TimeInterpolator):
|
|
"""PathInterpolator — 路径插值器"""
|
|
|
|
def __init__(self, controlX1: float = 0.0, controlY1: float = 0.0,
|
|
controlX2: float = 1.0, controlY2: float = 1.0):
|
|
super().__init__()
|
|
self._cx1 = controlX1
|
|
self._cy1 = controlY1
|
|
self._cx2 = controlX2
|
|
self._cy2 = controlY2
|
|
|
|
def getInterpolation(self, input_: float) -> float:
|
|
# Cubic bezier approximation
|
|
t = input_
|
|
return (3 * self._cy1 * t * (1 - t) ** 2 +
|
|
3 * self._cy2 * t ** 2 * (1 - t) +
|
|
t ** 3)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# AnimatorListener
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class AnimatorListener(Stub):
|
|
"""AnimatorListener — 动画监听器"""
|
|
|
|
def onAnimationStart(self, animation: "Animator"):
|
|
pass
|
|
|
|
def onAnimationEnd(self, animation: "Animator"):
|
|
pass
|
|
|
|
def onAnimationCancel(self, animation: "Animator"):
|
|
pass
|
|
|
|
def onAnimationRepeat(self, animation: "Animator"):
|
|
pass
|
|
|
|
|
|
class AnimatorPauseListener(Stub):
|
|
"""AnimatorPauseListener — 动画暂停监听器"""
|
|
|
|
def onAnimationPause(self, animation: "Animator"):
|
|
pass
|
|
|
|
def onAnimationResume(self, animation: "Animator"):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Animator
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class Animator(Stub):
|
|
"""Animator — 动画基类"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._duration: int = 300
|
|
self._start_delay: int = 0
|
|
self._interpolator: Optional[TimeInterpolator] = None
|
|
self._listeners: List[AnimatorListener] = []
|
|
self._pause_listeners: List[AnimatorPauseListener] = []
|
|
self._running: bool = False
|
|
self._started: bool = False
|
|
self._paused: bool = False
|
|
self._start_time: float = 0.0
|
|
|
|
def start(self):
|
|
self._running = True
|
|
self._started = True
|
|
self._start_time = _time.time() + self._start_delay / 1000.0
|
|
self._notify_start()
|
|
|
|
def end(self):
|
|
if self._running:
|
|
self._running = False
|
|
self._notify_end()
|
|
|
|
def cancel(self):
|
|
if self._running:
|
|
self._running = False
|
|
self._started = False
|
|
self._notify_cancel()
|
|
|
|
def pause(self):
|
|
if self._running and not self._paused:
|
|
self._paused = True
|
|
for l in self._pause_listeners:
|
|
l.onAnimationPause(self)
|
|
|
|
def resume(self):
|
|
if self._paused:
|
|
self._paused = False
|
|
for l in self._pause_listeners:
|
|
l.onAnimationResume(self)
|
|
|
|
def isRunning(self) -> bool:
|
|
return self._running
|
|
|
|
def isStarted(self) -> bool:
|
|
return self._started
|
|
|
|
def isPaused(self) -> bool:
|
|
return self._paused
|
|
|
|
def addListener(self, listener: AnimatorListener):
|
|
if listener not in self._listeners:
|
|
self._listeners.append(listener)
|
|
|
|
def removeListener(self, listener: AnimatorListener):
|
|
if listener in self._listeners:
|
|
self._listeners.remove(listener)
|
|
|
|
def getListeners(self) -> List[AnimatorListener]:
|
|
return list(self._listeners)
|
|
|
|
def addPauseListener(self, listener: AnimatorPauseListener):
|
|
if listener not in self._pause_listeners:
|
|
self._pause_listeners.append(listener)
|
|
|
|
def removePauseListener(self, listener: AnimatorPauseListener):
|
|
if listener in self._pause_listeners:
|
|
self._pause_listeners.remove(listener)
|
|
|
|
def setDuration(self, duration: int) -> "Animator":
|
|
self._duration = duration
|
|
return self
|
|
|
|
def getDuration(self) -> int:
|
|
return self._duration
|
|
|
|
def setStartDelay(self, startDelay: int) -> "Animator":
|
|
self._start_delay = startDelay
|
|
return self
|
|
|
|
def getStartDelay(self) -> int:
|
|
return self._start_delay
|
|
|
|
def setInterpolator(self, interpolator: TimeInterpolator):
|
|
self._interpolator = interpolator
|
|
|
|
def getInterpolator(self) -> Optional[TimeInterpolator]:
|
|
return self._interpolator
|
|
|
|
def clone(self) -> "Animator":
|
|
cloned = Animator()
|
|
cloned._duration = self._duration
|
|
cloned._start_delay = self._start_delay
|
|
cloned._interpolator = self._interpolator
|
|
return cloned
|
|
|
|
def _notify_start(self):
|
|
for l in self._listeners:
|
|
l.onAnimationStart(self)
|
|
|
|
def _notify_end(self):
|
|
for l in self._listeners:
|
|
l.onAnimationEnd(self)
|
|
|
|
def _notify_cancel(self):
|
|
for l in self._listeners:
|
|
l.onAnimationCancel(self)
|
|
|
|
def _notify_repeat(self):
|
|
for l in self._listeners:
|
|
l.onAnimationRepeat(self)
|
|
|
|
def toString(self) -> str:
|
|
return f"Animator@{hex(id(self))}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ValueAnimator.AnimatorUpdateListener
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ValueAnimator:
|
|
class AnimatorUpdateListener(Stub):
|
|
"""AnimatorUpdateListener — 值更新监听器"""
|
|
|
|
def onAnimationUpdate(self, animation: "ValueAnimator"):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ValueAnimator
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ValueAnimator(Animator):
|
|
"""ValueAnimator — 值动画"""
|
|
|
|
INFINITE = -1
|
|
RESTART = 1
|
|
REVERSE = 2
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._values: List[Any] = []
|
|
self._animated_value: Any = None
|
|
self._animated_fraction: float = 0.0
|
|
self._repeat_count: int = 0
|
|
self._repeat_mode: int = self.RESTART
|
|
self._evaluator: Optional[TypeEvaluator] = None
|
|
self._update_listeners: List[ValueAnimator.AnimatorUpdateListener] = []
|
|
self._current_play_time: int = 0
|
|
self._reverse_direction: bool = False
|
|
self._property_name: Optional[str] = None
|
|
|
|
@staticmethod
|
|
def ofInt(*values: int) -> "ValueAnimator":
|
|
anim = ValueAnimator()
|
|
anim._values = list(values)
|
|
anim._evaluator = IntEvaluator()
|
|
return anim
|
|
|
|
@staticmethod
|
|
def ofFloat(*values: float) -> "ValueAnimator":
|
|
anim = ValueAnimator()
|
|
anim._values = list(values)
|
|
anim._evaluator = FloatEvaluator()
|
|
return anim
|
|
|
|
@staticmethod
|
|
def ofObject(*values: Any) -> "ValueAnimator":
|
|
anim = ValueAnimator()
|
|
anim._values = list(values)
|
|
return anim
|
|
|
|
def setIntValues(self, *values: int):
|
|
self._values = list(values)
|
|
|
|
def setFloatValues(self, *values: float):
|
|
self._values = list(values)
|
|
|
|
def setObjectValues(self, *values: Any):
|
|
self._values = list(values)
|
|
|
|
def getAnimatedValue(self) -> Any:
|
|
return self._animated_value
|
|
|
|
def getAnimatedFraction(self) -> float:
|
|
return self._animated_fraction
|
|
|
|
def setRepeatCount(self, count: int):
|
|
self._repeat_count = count
|
|
|
|
def getRepeatCount(self) -> int:
|
|
return self._repeat_count
|
|
|
|
def setRepeatMode(self, mode: int):
|
|
self._repeat_mode = mode
|
|
|
|
def getRepeatMode(self) -> int:
|
|
return self._repeat_mode
|
|
|
|
def setEvaluator(self, evaluator: TypeEvaluator):
|
|
self._evaluator = evaluator
|
|
|
|
def getEvaluator(self) -> Optional[TypeEvaluator]:
|
|
return self._evaluator
|
|
|
|
def setCurrentPlayTime(self, playTime: int):
|
|
self._current_play_time = playTime
|
|
if self._duration > 0:
|
|
self._animated_fraction = playTime / self._duration
|
|
self._evaluate()
|
|
|
|
def getCurrentPlayTime(self) -> int:
|
|
return self._current_play_time
|
|
|
|
def reverse(self):
|
|
self._reverse_direction = not self._reverse_direction
|
|
self.start()
|
|
|
|
def addUpdateListener(self, listener: ValueAnimator.AnimatorUpdateListener):
|
|
if listener not in self._update_listeners:
|
|
self._update_listeners.append(listener)
|
|
|
|
def removeUpdateListener(self, listener: ValueAnimator.AnimatorUpdateListener):
|
|
if listener in self._update_listeners:
|
|
self._update_listeners.remove(listener)
|
|
|
|
def removeAllUpdateListeners(self):
|
|
self._update_listeners.clear()
|
|
|
|
def start(self):
|
|
super().start()
|
|
if len(self._values) >= 2:
|
|
self._evaluate()
|
|
|
|
def _evaluate(self):
|
|
if len(self._values) >= 2 and self._evaluator:
|
|
fraction = self._animated_fraction
|
|
if self._interpolator:
|
|
fraction = self._interpolator.getInterpolation(fraction)
|
|
self._animated_value = self._evaluator.evaluate(
|
|
fraction, self._values[0], self._values[-1]
|
|
)
|
|
for l in self._update_listeners:
|
|
l.onAnimationUpdate(self)
|
|
|
|
def clone(self) -> "ValueAnimator":
|
|
cloned = ValueAnimator()
|
|
cloned._values = list(self._values)
|
|
cloned._duration = self._duration
|
|
cloned._start_delay = self._start_delay
|
|
cloned._repeat_count = self._repeat_count
|
|
cloned._repeat_mode = self._repeat_mode
|
|
cloned._evaluator = self._evaluator
|
|
cloned._interpolator = self._interpolator
|
|
return cloned
|
|
|
|
def toString(self) -> str:
|
|
return f"ValueAnimator@{hex(id(self))}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ObjectAnimator
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ObjectAnimator(ValueAnimator):
|
|
"""ObjectAnimator — 对象属性动画"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._target: Any = None
|
|
self._property_name: Optional[str] = None
|
|
|
|
@staticmethod
|
|
def ofInt(target: Any, propertyName: str, *values: int) -> "ObjectAnimator":
|
|
anim = ObjectAnimator()
|
|
anim._target = target
|
|
anim._property_name = propertyName
|
|
anim._values = list(values)
|
|
anim._evaluator = IntEvaluator()
|
|
return anim
|
|
|
|
@staticmethod
|
|
def ofFloat(target: Any, propertyName: str, *values: float) -> "ObjectAnimator":
|
|
anim = ObjectAnimator()
|
|
anim._target = target
|
|
anim._property_name = propertyName
|
|
anim._values = list(values)
|
|
anim._evaluator = FloatEvaluator()
|
|
return anim
|
|
|
|
@staticmethod
|
|
def ofObject(target: Any, propertyName: str, *values: Any) -> "ObjectAnimator":
|
|
anim = ObjectAnimator()
|
|
anim._target = target
|
|
anim._property_name = propertyName
|
|
anim._values = list(values)
|
|
return anim
|
|
|
|
def setPropertyName(self, propertyName: str):
|
|
self._property_name = propertyName
|
|
|
|
def getPropertyName(self) -> Optional[str]:
|
|
return self._property_name
|
|
|
|
def getTarget(self) -> Any:
|
|
return self._target
|
|
|
|
def setTarget(self, target: Any):
|
|
self._target = target
|
|
|
|
def setProperty(self, property_: Any):
|
|
pass
|
|
|
|
def setupStartValues(self):
|
|
pass
|
|
|
|
def setupEndValues(self):
|
|
pass
|
|
|
|
def clone(self) -> "ObjectAnimator":
|
|
cloned = ObjectAnimator()
|
|
cloned._target = self._target
|
|
cloned._property_name = self._property_name
|
|
cloned._values = list(self._values)
|
|
cloned._duration = self._duration
|
|
cloned._start_delay = self._start_delay
|
|
cloned._evaluator = self._evaluator
|
|
cloned._interpolator = self._interpolator
|
|
return cloned
|
|
|
|
def toString(self) -> str:
|
|
return f"ObjectAnimator{{property={self._property_name}, target={self._target}}}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# AnimatorSet
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class AnimatorSet(Animator):
|
|
"""AnimatorSet — 动画集合"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._children: List[Animator] = []
|
|
self._play_order: List[Animator] = []
|
|
|
|
def play(self, anim: Animator) -> "AnimatorSet.Builder":
|
|
return self.Builder(self, anim)
|
|
|
|
def playSequentially(self, *items: Animator):
|
|
self._children = list(items)
|
|
self._play_order = list(items)
|
|
|
|
def playTogether(self, *items: Animator):
|
|
self._children = list(items)
|
|
self._play_order = list(items)
|
|
|
|
def start(self):
|
|
super().start()
|
|
for anim in self._play_order:
|
|
anim.start()
|
|
|
|
def end(self):
|
|
super().end()
|
|
for anim in self._play_order:
|
|
anim.end()
|
|
|
|
def cancel(self):
|
|
super().cancel()
|
|
for anim in self._play_order:
|
|
anim.cancel()
|
|
|
|
class Builder(Stub):
|
|
"""AnimatorSet.Builder — 构建器"""
|
|
|
|
def __init__(self, parent: "AnimatorSet", anim: Animator):
|
|
super().__init__()
|
|
self._parent = parent
|
|
self._current = anim
|
|
|
|
def with_(self, anim: Animator) -> "AnimatorSet.Builder":
|
|
self._parent._play_order.append(anim)
|
|
return self
|
|
|
|
def before(self, anim: Animator) -> "AnimatorSet.Builder":
|
|
self._parent._play_order.append(anim)
|
|
return self
|
|
|
|
def after(self, anim: Animator) -> "AnimatorSet.Builder":
|
|
idx = self._parent._play_order.index(self._current) if self._current in self._parent._play_order else -1
|
|
if idx >= 0:
|
|
self._parent._play_order.insert(idx + 1, anim)
|
|
else:
|
|
self._parent._play_order.append(anim)
|
|
return self
|
|
|
|
def after(self, delay: int) -> "AnimatorSet.Builder":
|
|
return self
|
|
|
|
def toString(self) -> str:
|
|
return f"AnimatorSet{{{len(self._children)} animations}}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TimeAnimator
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TimeAnimator(ValueAnimator):
|
|
"""TimeAnimator — 时间动画"""
|
|
|
|
class TimeListener(Stub):
|
|
"""TimeListener — 时间监听器"""
|
|
|
|
def onTimeUpdate(self, animation: "TimeAnimator", elapsedTime: int, totalTime: int):
|
|
pass
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._time_listener: Optional[TimeAnimator.TimeListener] = None
|
|
self._elapsed_time: int = 0
|
|
self._total_time: int = 0
|
|
|
|
def setTimeListener(self, listener: TimeAnimator.TimeListener):
|
|
self._time_listener = listener
|
|
|
|
def start(self):
|
|
super().start()
|
|
if self._time_listener:
|
|
self._time_listener.onTimeUpdate(self, self._elapsed_time, self._total_time)
|
|
|
|
def toString(self) -> str:
|
|
return f"TimeAnimator@{hex(id(self))}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Keyframe
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class Keyframe(Stub):
|
|
"""Keyframe — 关键帧"""
|
|
|
|
def __init__(self, fraction: float):
|
|
super().__init__()
|
|
self._fraction: float = fraction
|
|
self._value: Any = None
|
|
self._type: Optional[type] = None
|
|
self._interpolator: Optional[TimeInterpolator] = None
|
|
|
|
@staticmethod
|
|
def ofInt(fraction: float, value: int) -> "Keyframe":
|
|
kf = Keyframe(fraction)
|
|
kf._value = value
|
|
kf._type = int
|
|
return kf
|
|
|
|
@staticmethod
|
|
def ofFloat(fraction: float, value: float) -> "Keyframe":
|
|
kf = Keyframe(fraction)
|
|
kf._value = value
|
|
kf._type = float
|
|
return kf
|
|
|
|
@staticmethod
|
|
def ofObject(fraction: float, value: Any = None) -> "Keyframe":
|
|
kf = Keyframe(fraction)
|
|
kf._value = value
|
|
return kf
|
|
|
|
def setValue(self, value: Any):
|
|
self._value = value
|
|
|
|
def getValue(self) -> Any:
|
|
return self._value
|
|
|
|
def setFraction(self, fraction: float):
|
|
self._fraction = fraction
|
|
|
|
def getFraction(self) -> float:
|
|
return self._fraction
|
|
|
|
def getType(self) -> Optional[type]:
|
|
return self._type
|
|
|
|
def setInterpolator(self, interpolator: Optional[TimeInterpolator]):
|
|
self._interpolator = interpolator
|
|
|
|
def getInterpolator(self) -> Optional[TimeInterpolator]:
|
|
return self._interpolator
|
|
|
|
def clone(self) -> "Keyframe":
|
|
kf = Keyframe(self._fraction)
|
|
kf._value = self._value
|
|
kf._type = self._type
|
|
kf._interpolator = self._interpolator
|
|
return kf
|
|
|
|
def toString(self) -> str:
|
|
return f"Keyframe{{fraction={self._fraction}, value={self._value}}}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PropertyValuesHolder
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PropertyValuesHolder(Stub):
|
|
"""PropertyValuesHolder — 属性值持有者"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._property_name: str = ""
|
|
self._values: List[Any] = []
|
|
self._animated_value: Any = None
|
|
self._evaluator: Optional[TypeEvaluator] = None
|
|
self._keyframes: List[Keyframe] = []
|
|
|
|
@staticmethod
|
|
def ofInt(propertyName: str, *values: int) -> "PropertyValuesHolder":
|
|
holder = PropertyValuesHolder()
|
|
holder._property_name = propertyName
|
|
holder._values = list(values)
|
|
return holder
|
|
|
|
@staticmethod
|
|
def ofFloat(propertyName: str, *values: float) -> "PropertyValuesHolder":
|
|
holder = PropertyValuesHolder()
|
|
holder._property_name = propertyName
|
|
holder._values = list(values)
|
|
return holder
|
|
|
|
@staticmethod
|
|
def ofObject(propertyName: str, *values: Any) -> "PropertyValuesHolder":
|
|
holder = PropertyValuesHolder()
|
|
holder._property_name = propertyName
|
|
holder._values = list(values)
|
|
return holder
|
|
|
|
@staticmethod
|
|
def ofKeyframes(propertyName: str, *keyframes: Keyframe) -> "PropertyValuesHolder":
|
|
holder = PropertyValuesHolder()
|
|
holder._property_name = propertyName
|
|
holder._keyframes = list(keyframes)
|
|
return holder
|
|
|
|
def setPropertyName(self, propertyName: str):
|
|
self._property_name = propertyName
|
|
|
|
def getPropertyName(self) -> str:
|
|
return self._property_name
|
|
|
|
def getAnimatedValue(self) -> Any:
|
|
return self._animated_value
|
|
|
|
def setEvaluator(self, evaluator: TypeEvaluator):
|
|
self._evaluator = evaluator
|
|
|
|
def clone(self) -> "PropertyValuesHolder":
|
|
holder = PropertyValuesHolder()
|
|
holder._property_name = self._property_name
|
|
holder._values = list(self._values)
|
|
holder._keyframes = list(self._keyframes)
|
|
holder._evaluator = self._evaluator
|
|
return holder
|
|
|
|
def toString(self) -> str:
|
|
return f"PropertyValuesHolder{{property={self._property_name}}}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TypeConverter
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TypeConverter(Stub):
|
|
"""TypeConverter — 类型转换器"""
|
|
|
|
def convert(self, value: Any) -> Any:
|
|
return value
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# LayoutTransition
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class LayoutTransition(Stub):
|
|
"""LayoutTransition — 布局过渡动画"""
|
|
|
|
APPEARING = 0
|
|
CHANGE_APPEARING = 1
|
|
CHANGE_DISAPPEARING = 2
|
|
DISAPPEARING = 3
|
|
CHANGING = 4
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._animators: Dict[int, Optional[Animator]] = {
|
|
self.APPEARING: None,
|
|
self.CHANGE_APPEARING: None,
|
|
self.CHANGE_DISAPPEARING: None,
|
|
self.DISAPPEARING: None,
|
|
self.CHANGING: None,
|
|
}
|
|
|
|
def setAnimator(self, transitionType: int, animator: Animator):
|
|
self._animators[transitionType] = animator
|
|
|
|
def getAnimator(self, transitionType: int) -> Optional[Animator]:
|
|
return self._animators.get(transitionType)
|
|
|
|
def startTransition(self, container: Any, transitionType: int):
|
|
pass
|
|
|
|
def endTransition(self, transitionType: int):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"LayoutTransition@{hex(id(self))}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# StateListAnimator
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class StateListAnimator(Stub):
|
|
"""StateListAnimator — 状态列表动画"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._tuples: List[Tuple[List[int], Animator]] = []
|
|
self._target: Any = None
|
|
|
|
def addState(self, specs: List[int], animator: Animator):
|
|
self._tuples.append((specs, animator))
|
|
|
|
def setTarget(self, target: Any):
|
|
self._target = target
|
|
|
|
def clone(self) -> "StateListAnimator":
|
|
cloned = StateListAnimator()
|
|
cloned._tuples = list(self._tuples)
|
|
return cloned
|
|
|
|
def toString(self) -> str:
|
|
return f"StateListAnimator{{{len(self._tuples)} states}}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# __all__
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
__all__ = [
|
|
"Animator",
|
|
"ValueAnimator",
|
|
"ObjectAnimator",
|
|
"AnimatorSet",
|
|
"TimeAnimator",
|
|
"AnimatorListener",
|
|
"AnimatorPauseListener",
|
|
"TypeEvaluator",
|
|
"FloatEvaluator",
|
|
"IntEvaluator",
|
|
"PointFEvaluator",
|
|
"RectEvaluator",
|
|
"ArgbEvaluator",
|
|
"TypeConverter",
|
|
"Keyframe",
|
|
"PropertyValuesHolder",
|
|
"LayoutTransition",
|
|
"StateListAnimator",
|
|
"TimeInterpolator",
|
|
"AccelerateDecelerateInterpolator",
|
|
"AccelerateInterpolator",
|
|
"AnticipateInterpolator",
|
|
"AnticipateOvershootInterpolator",
|
|
"BounceInterpolator",
|
|
"CycleInterpolator",
|
|
"DecelerateInterpolator",
|
|
"LinearInterpolator",
|
|
"OvershootInterpolator",
|
|
"PathInterpolator",
|
|
] |