モジュール 4 タスク 1: フリックスクロールの実装
- 概要
-
- マウスイベントを処理する
- バウンドアニメーションを有効にする
- フリックアニメーションを調整する
はじめに
「モジュール 4 タスク 1」では、マウスイベントの機能と物理エンジンによるアニメーションについて検証し、「モジュール 2 タスク 2」の ScrollControl.fx ノードで紹介したスクロールコントロール機能にフリックスクロールを追加します。今回のタスクの手順を終える前に、「モジュール 2 タスク 2」のスクロールコントロール機能を再確認してください。
フリックスクロールは、マウスを放したときにマウスドラッグをスクロールアニメーションに変換することで実現されます。アニメーションでスクロールコントロールのエレベータの位置を更新し、それに合わせてサムネイル画像の壁を動かします。画像の壁がサムネイル配列の終端を超えてスクロールする場合は、バウンドアニメーション効果が働きます。
プロジェクトの実行
- モジュール 4 タスク 1 NetBeans プロジェクトをダウンロードして、NetBeans IDE を開きます。
- プロジェクトを実行します。
図 1
アーキテクチャー
このタスクでは、ScrollControl.fx にフリックスクロール機能を追加します。
図 2
マウスイベントの処理
フリックスクロールは、ドラッグジェスチャー、つまりマウスの左ボタンをクリックし、そのままドラッグして、ボタンを放すことにより開始されます。マウスボタンを放したときに、ジェスチャーが十分な速度であれば、フリックアニメーションが開始されます。そうでない場合は、ドラッグジェスチャーにより壁のサムネイルが単にスクロールされるだけです。
ローカル変数 lastDragTime、lastDragX、および dragSpeed は、ドラッグジェスチャーでのマウスの動きを監視するために使用されます。これに関係する関数は、onMousePressed、onMouseDragged、onMouseReleased の 3 つです。これらの変数は、onMousePressed で初期化されます。ユーザーがマウスをドラッグするのに合わせて、onMouseDragged で更新されます。最後に、onMouseReleased で評価され、アニメーションを表示するかどうかが決定されます。
次のソースコードサンプルに示す onMouseDragged 関数は、ユーザーがマウスをドラッグすると呼び出されます。MouseEvent 関数の dragX の値は、前の値からの差分です。マウスの動きが小さいと、壁はスクロールしません。したがって、MouseEvent の dragX の値が、一定のしきい値を超えることが必要になります。
dragSpeed は単に、マウスの移動距離を移動時間で除算して計算されます (注 距離 = 速度 * 時間)。
onMouseDragged: function(evt: MouseEvent): Void {
var dragTime = Duration.valueOf(java.lang.System.currentTimeMillis());
if (java.lang.Math.abs(evt.dragX) > Constants.FLICK_DRAG_THRESHOLD) {
// Set the elevator's dragging flag to prevent its
// overlay from recentering on every mouse event.
dragging = true;
position = posAnchor - evt.dragX / (contentWidth - windowWidth);
// Monitor the dragging speed.
dragSpeed = (evt.dragX - lastDragX) /
dragTime.sub(lastDragTime).toMillis();
if (dragSpeed > Constants.FLICK_MAX_SPEED) {
dragSpeed = Constants.FLICK_MAX_SPEED;
} else if (dragSpeed < -Constants.FLICK_MAX_SPEED) {
dragSpeed = -Constants.FLICK_MAX_SPEED;
}
lastDragTime = dragTime;
lastDragX = evt.dragX;
}
}
onMouseReleased 関数は、それより複雑です。マウスボタンを放したとき、onMouseReleased は次の条件に基づいて、フリックアニメーションを表示するかどうかを決定します。
ユーザーが
Constants.FLICK_DRAG_THRESHOLDの値よりも大きくマウスをドラッグしたか。FLICK_DRAG_THRESHOLDは、スクロールを発生させるための、ピクセル単位で表したマウスの最小ドラッグ距離です。ユーザーが通常のスクロール制限を越えて壁をドラッグしたか。
Constants.FLICK_TIME_THRESHOLD値よりも長く壁の動作が持続するマウスのドラッグ速度か。FLICK_TIME_THRESHOLDは、アニメーションを表示するための最小時間です。
これらの条件に適合した場合、壁が新しい位置にスクロールするアニメーションのための Timeline が新しい位置に作成されます。Timeline によって、flickOffset の値が補間されます。flickOffset の値が変更されると、position 変数が更新されます。position は Wall.scrollPosition の逆の値にバインドされているため、position が更新されると、壁はスクロールします。「モジュール 2 タスク 2」の「算術計算」を参照してください。
flickTimeline = Timeline {
keyFrames: [
at (0s) {
flickOffset => scrollOffset tween flickInterpolator
},
KeyFrame {
time: Duration.valueOf(restTime)
action: bounce
values: [
flickOffset => restOffset tween flickInterpolator
]
}
];
};
補間は javafx.animation.Interpolator では行われず、カスタムの FlickInterpolator に、アニメーション用のモーションの等加速度式が指定されています。FlickInterpolator は、javafx.animation.Interpolator を拡張して interpolate 関数をオーバーライドしたものです。interpolate 関数は、KeyFrame の継続時間中に繰り返し呼び出され、指定された KeyFrame の開始値と終了値の間で値のシーケンスを効果的に作成します。
fraction 引数は、KeyFrame 継続時間を小数で表したものです。たとえば、fraction の値が .5 の場合、KeyFrame の継続時間の半分が経過したことを表します。startValue は、KeyFrame の開始時点の値です。interpolate 関数のコントラクトは、startValue と endValue の間の値を返す関数になります。
interpolate 関数は等加速度式を使用して、スクロール制限に達して停止するための、壁の初期速度を決定します。
x = x0 + v0 * t + a * t^2 / 2
したがって、v0 = (x0 - x + a * t^2 / 2) / t となります。ここで、x0 は終了後の初期位置、x はスクロール制限の位置、a は等加速度、t はバウンドさせるための一定の時間を表します。
class FlickInterpolator extends Interpolator {
// Initial position
var x0: Number;
// Initial velocity
var v0: Number;
// The time at which the object comes to rest.
var t1: Number;
override function interpolate(startValue: java.lang.Object,
endValue: java.lang.Object,fraction: Number) :
java.lang.Object {
// The sign of the acceleration parameter is based on the
// direction of motion.
var a : Number = bind if (v0 > 0) {
Constants.FLICK_ACCELERATION;
} else {
-Constants.FLICK_ACCELERATION;
}
// The interpolation always begins at t = 0 so
// t = t0 + (t1 - t0) * fraction becomes
// t = t1 * fraction
var t = fraction * t1;
// Apply the motion formula for constant acceleration.
return x0 + v0 * t + a * t * t / 2;
}
}
バウンドアニメーション
フリックアニメーションが動いた場合、またはユーザーがサムネイルの列を越えて壁をドラッグした場合、バウンドアニメーションが表示されます。バウンドアニメーションは、FlickInterpolator を使用して、スクロール制限に一定の時間で壁を戻すことを簡単に表現したものです。
var restOffset = 0.0;
var a = -Constants.FLICK_ACCELERATION;
if (scrollOffset <= 0) {
restOffset = -(contentWidth - windowWidth);
a *= -1;
}
// Compute the initial rebound velocity based on the position and
// the defined bounce duration.
var v0 = (restOffset - scrollOffset -
a * Constants.FLICK_BOUNCE_TIME * Constants.FLICK_BOUNCE_TIME / 2) /
Constants.FLICK_BOUNCE_TIME;
// Create a motion formula interpolator for the bounce animation.
var flickInterpolator = FlickInterpolator {
x0: scrollOffset
v0: v0
t1: Constants.FLICK_BOUNCE_TIME;
}
フリックアニメーションの調整
次の表に示されているのは、Constants.fx に追加され、フリックアニメーションの動作の調整に使用できる変数です。
| 定数 | 意味 | 値 |
|---|---|---|
FLICK_DRAG_THRESHOLD |
スクロールのトリガーを発生するために必要な、マウスドラッグの最小距離 (ピクセル単位)。 | 5 ピクセル |
FLICK_TIME_THRESHOLD |
フリックアニメーションの最小継続時間。これより短いと、アニメーションが短すぎて表示効果が得られません。 | 500 ミリ秒 |
FLICK_ACCELERATION |
フリック後のスクロールの加速 (ピクセル / ms / ms 単位)。フリックの物理計算で、この値は (マイナスの値で) 摩擦抵抗を表します。 | - 0.00035 ピクセル / ms / ms |
FLICK_MAX_SPEED |
壁が (3500) ミリ秒以内でスクロールを停止するための、初期速度の最大制限値。 | - FLICK_ACCELERATION * 3500 |
FLICK_BOUNCE_LIMIT |
フリックアニメーションが行き過ぎることのできる距離 (ピクセル単位)。 | 100 ピクセル |
FLICK_BOUNCE_TIME |
壁が行き過ぎたときにバウンド (逆方向にスクロール) する秒数 (ミリ秒単位)。 | 750 ミリ秒 |
