スプリング曲線アニメーションの概要
ArkUIでは、LinearやEase、EaseInといった標準的なアニメーション曲線に加え、物理学のバネ・質量・ダンパーモデルに基づいた「スプリング曲線」を利用できます。この曲線を使用することで、アニメーションが目標値を超えて揺らぎ、最終的に収束するような、現実世界の物理挙動に近いインタラクティブな演出が可能になります。
ArkUIでは主に、springCurveによる詳細な物理パラメータ設定と、springMotion系によるレスポンシブな動きの2通りの実装方法が提供されています。
1. springCurveによる詳細設定
springCurveは、物体の質量や剛性などの物理量に基づいたアニメーションを生成します。インターフェースは以下の通りです。
springCurve(velocity: number, mass: number, stiffness: number, damping: number)
- velocity(初速度): アニメーション開始時の物体の速度。
- mass(質量): システムの重さ。値が大きいほど慣性が強くなり、動きが重くなります。
- stiffness(剛性): バネの強さ。値が大きいほど元の位置に戻ろうとする力が強くなり、振動が速くなります。
- damping(減衰比): 振動を抑える抵抗力。値が小さいと長く揺れ続け、大きいとすぐに停止します。
実装例:速度変化によるバウンス効果
以下の例では、ボタン押下時に異なる初速度を与え、要素の水平移動にスプリング効果を適用しています。
import curves from '@ohos.curves';
@Entry
@Component
struct PhysicsSpringComponent {
@State private elementOffset: number = 0;
private applySpringAnimation(initialVelocity: number) {
// ターゲットを一旦ずらしてから0に戻る動き
this.elementOffset = -20;
animateTo({
duration: 1500,
curve: curves.springCurve(initialVelocity, 1, 150, 10)
}, () => {
this.elementOffset = 0;
})
}
build() {
Column() {
// アニメーション対象のコンポーネント
Circle({ width: 60, height: 60 })
.fill(Color.Red)
.translate({ x: this.elementOffset })
.margin(50)
Row({ space: 20 }) {
Button("Low Speed")
.onClick(() => this.applySpringAnimation(20))
Button("High Speed")
.onClick(() => this.applySpringAnimation(100))
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
2. springMotionとresponsiveSpringMotion
インタラクティブなユーザー操作(ドラッグなど)には、より柔軟なspringMotionおよびresponsiveSpringMotionが適しています。これらは物理量ではなく、直感的な「応答時間」と「減衰比」で定義されます。
springMotion(response?: number, dampingFraction?: number, overlapDuration?: number)
responsiveSpringMotion(response?: number, dampingFraction?: number, overlapDuration?: number)
- response(応答時間): バネが1往復する周期に近い概念。値が小さいほど機敏に反応します。
- dampingFraction(減衰比): 1.0でクリティカルダンピング(揺れずに停止)、1.0未満で振動が発生します。
- overlapDuration(オーバーラップ時間): 連続したアニメーションが重なった際の遷移時間。
実装例:ドラッグ追従と自動復帰
指の動きに追従する際はresponsiveSpringMotionを使用し、指を離して元の位置に戻る際にはspringMotionを使用することで、滑らかな操作感を実現します。
import curves from '@ohos.curves';
@Entry
@Component
struct InteractiveSpringBall {
@State private ballX: number = 150;
@State private ballY: number = 150;
private readonly radius: number = 30;
build() {
Stack() {
Circle({ width: this.radius * 2, height: this.radius * 2 })
.fill(Color.Blue)
.position({ x: this.ballX, y: this.ballY })
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Move) {
// ドラッグ中は追従性を高める responsiveSpringMotion
animateTo({ curve: curves.responsiveSpringMotion(0.35, 0.7) }, () => {
this.ballX = event.touches[0].screenX - this.radius;
this.ballY = event.touches[0].screenY - this.radius;
})
} else if (event.type === TouchType.Up) {
// 離した時は自然な揺り戻しの springMotion
animateTo({ curve: curves.springMotion(0.6, 0.8) }, () => {
this.ballX = 150;
this.ballY = 150;
})
}
})
}
.width("100%")
.height("100%")
.backgroundColor("#F2F2F2")
}
}
springCurveは厳密な物理挙動をシミュレートしたい場合に適しており、springMotionはより感覚的なUIの調整や、動的なターゲット位置への追従において優れた効果を発揮します。