動的スクロールの実装を作成するための優れたアルゴリズムは何ですか? この機能は、カスタム UI リストでテストされます。私はモバイル デバイス (この機能が組み込まれていないデバイス) をターゲットにしていますが、別のプログラミング分野のアルゴリズムやコード例も適している可能性があります。
6 に答える
最近、自分で実装しました。これらは私が取ったステップです。
- カーソル(マウスカーソルまたは指)の速度を測定する必要があります
- シンプルな素粒子物理ループを実装します。その方法に関する情報は、ここで見つけることができます
- スクロール プレーンの幅とビューポートの幅から得られる計算を使用して、パーティクルの「境界」を指定します
- マウスの速度と粒子の速度の差を粒子の速度に連続的に追加します。これにより、粒子の速度は、マウスが移動している限りマウスの速度と「一致」します。
- ユーザーが指を離したらすぐに、手順 4 の実行を停止します。物理ループは慣性を処理します。
- 「バンパー」マージンや、動きを計算するためにゼノのパラドックスで動作するスムーズ スクロールの「アンカー」ポイントなど、個人的な装飾を追加します。
- 私はほとんど忘れていました: 上から得られた座標を取得し、それをスクロール プレーンの位置として使用します。
おそらく、このコードをすぐにオープン ソース化する予定です。これはいつまで必要ですか?
編集:リンクを変更しました。申し訳ありませんが、少し間違ったページを指摘しました。edit2: かどうか? とにかく、私がリンクした元のページは、現在リンクされているページの最初のリンクでした。
これは最初に尋ねられたので、私はペストリーキットのソースコードを注意深く読みました。このフレームワークでは、Apple は JavaScript で動的スクロールを正確に複製しました。素粒子物理学のループはありません。タッチの速度は、指が離された正確な瞬間に測定されます。その時点から、速度を入力パラメーターとして使用する単純なイージング関数を使用して、スクロールがアニメーション化されます。
モバイル GUI フレームワークにスクローラー ウィジェットを追加したので、ここでソリューションを共有したいと思います。
これはかなり複雑な問題なので、次のように、ある程度独立した小さなサブタスクに分割することにしました。
基本的なスクロール機能: このタスクは、ドラッグの距離と方向に応じてコンテンツをスクロールするという最も単純な方法でドラッグ イベントを処理することで構成されていました。これは比較的簡単に実装できました。唯一の注意点は、ドラッグ操作を開始するタイミングと、スクロール可能な領域内の子ウィジェットにタップ イベントを渡すタイミングを知ることでした。
スクロール慣性: これが一番難しかったです。ここでの考え方は、ユーザーが指を離した後もしばらくスクロールを続け、完全に停止するまで速度を落とすというものです。このためには、スクロール速度を把握する必要がありました。残念ながら、単一のサンプルから速度を計算するのは正確ではないため、ユーザーがスクロールしている間、最後の N 個のモーション イベントを循環バッファーに記録し、各イベントが発生した時刻も記録します。N=4 は、iPhone と HP TouchPad で問題なく動作することがわかりました。指を離すと、記録されたモーションから慣性スクロールのおおよその開始速度を計算できます。負の加速度係数を定義し、標準的な運動公式を使用しました (こちらを参照)。) スクロールをうまく停止させます。移動中にスクロール位置が境界に達した場合は、範囲外にならないように速度を 0 にリセットします (突然の停止については次に説明します)。
柔軟なスクロール制限: スクロールが最後に達したときに突然停止するのではなく、ウィジェットをスクロールさせたいと思いましたが、抵抗を提供しました。このために、ウィジェットの寸法の関数として定義した量だけ、両端で許容されるスクロール範囲を拡張しました。両端に幅または高さの半分を追加すると、うまく機能することがわかりました。スクロールに抵抗感を持たせるコツは、表示されるスクロール位置が範囲外の場合に調整することでした。これには、縮小と減速機能を使用しました (ここにはいくつかの優れたイージング機能があります)。
スプリングの動作: 有効な範囲を超えてスクロールできるようになったため、ユーザーが範囲外に置いた場合にスクローラーを有効な位置に戻す方法が必要でした。これは、スクローラーが範囲外の位置で停止したときにスクロール オフセットを調整することによって実現されます。私が見つけた調整機能は、現在の位置から目的の位置までの距離を定数で割り、オフセットをその量だけ移動することでした。定数が大きいほど動きが遅くなります。
スクロールバー: 最後の仕上げは、スクロールの開始時にフェードインし、終了時にフェードアウトするオーバーレイ スクロールバーを追加することでした。
Robert Penner のイージング関数を見たことがありますか?
http://www.robertpenner.com/easing/
IIRC これらはもともと Actionscript 用であり、長い間使用されてきました。
いろいろ探しました。すべてを組み合わせて、ソリューションを作成しました。
- ポインターを下げている間は、onTouchMove ハンドラーを呼び出すたびにピクセルの差を計算する必要があります。タッチ エンドで、この値を変数に保存します。たとえば、 diffPxと呼びます。
- 継続的な勢いのあるスクロールには requestAnimationFrame を使用します。各フレームで、 diffPxが制限値に達しない限り、コンテナをdiffPx =* 0.95 スクロールします (私は 0.25 を使用しました)。
- 1 つの重要な制限。ステップ 2 は、ポインターのdiffPxが制限値を超えている場合にのみ実行します (私は 5px を使用しました)。
https://developer.mozilla.org/ru/docs/Web/API/window/requestAnimationFrame
a) ユーザーがスクロールした速さの速度を取得する b) 彼が指を離すと、リストを自動スクロールしますが、ユーザーが持っていた初期速度で速度が低下します。