web-dev-qa-db-ja.com

同じ密度の異なるAndroidデバイスでの異なるフリング(スワイプ)速度

ユーザーが左/右にスワイプして次の\前の画像を表示できる独自の画像ビューアを作成しています。フリング速度に応じて画像の変化をアニメートしたい。

フリングジェスチャとその速度を検出するために、私はこれに従いました 基本的なジェスチャ検出 そして受け入れられた答えが示唆したように行いました:

public class SelectFilterActivity extends Activity implements OnClickListener
{

    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private GestureDetector gestureDetector;
    View.OnTouchListener gestureListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /* ... */

        // Gesture detection
        gestureDetector = new GestureDetector(this, new MyGestureDetector());
        gestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return gestureDetector.onTouchEvent(event);
            }
        };

    }

    class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                    return false;
                // right to left swipe
                if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
                }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
                }
            } catch (Exception e) {
                // nothing
            }
            return false;
        }

    }

問題は、同じ密度の異なるAndroidデバイスに対して異なる速度値(velocityXとvelocityY)を取得することです。基本的に、1つのデバイスではスワイプが遅く、感度が低いと感じ、他のデバイスでは感度が高すぎると感じることを意味します。

デバイスの「デフォルト」の最大速度と関係があるのではないかと思いました。これは、-を使用して取得できます。

ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity()

同じ密度の異なるデバイスでの結果は、期待したものと同じではありません。

    Samsung S I 480x800 density 1.5 Android 2.1
    getScaledMinimumFlingVelocity(): 75
    getScaledMaximumFlingVelocity(): 3600
    ViewConfiguration.MAXIMUM_FLING_VELOCITY = 4000

    HTC Desire 480x800 density 1.5 Android 2.3.3
    getScaledMinimumFlingVelocity(): 75
    getScaledMaximumFlingVelocity(): 6000
    ViewConfiguration.MAXIMUM_FLING_VELOCITY = 4000

    Samsung S III mini 480x800 density 1.5 Android 4.1
    getScaledMinimumFlingVelocity(): 75
    getScaledMaximumFlingVelocity(): 12000
    ViewConfiguration.MAXIMUM_FLING_VELOCITY = 8000

ViewConfiguration には、4.0より下のAndroidのMAXIMUM_FLING_VELOCITYに2つの異なる値があることもわかります。

同じ密度でほぼ同じAPIレベルの異なるデバイスが同じ最大速度を持たないのはなぜですか?ユーザーがスワイプジェスチャを行ったときに、異なるデバイスで同じエクスペリエンスを得るにはどうすればよいですか?最大速度データを使用して、すべてのAndroidデバイスで均一なエクスペリエンスを実現できますか?

22
Ron Tesler

私も同様の問題を抱えていました。 ViewConfigurationからの最大および最小フリング速度を直接操作する代わりに、速度を0から1の間の値に正規化できます。

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    float maxFlingVelocity    = ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity();
    float velocityPercentX    = velocityX / maxFlingVelocity;          // the percent is a value in the range of (0, 1]
    float normalizedVelocityX = velocityPercentX * PIXELS_PER_SECOND;  // where PIXELS_PER_SECOND is a device-independent measurement

言い換えると、velocityPercentXはフリングの「パワー」をパーセントで示し、normalizedVelocityXはアプリケーションロジック(デバイスに依存しないピクセルの画像幅など)に関する速度です。 )。

17
Bryan W. Wagner

同じ密度でほぼ同じAPIレベルの異なるデバイスが同じ最大速度を持たないのはなぜですか?

最小および最大速度パラメータはメーカーによって設定されます。異なるデバイスモデルは、リソース選択の目的で同じ密度バケットを使用することがよくありますが、通常は同じ密度を共有しません物理的密度。同じ解像度と同じ報告密度1.5の4 "電話と5"電話の存在を想定します。同じ物理速度で両方の画面をスワイプすることを想像してみてください。報告されたピクセル/秒は、両方の電話の解像度と報告された密度が同じであるにもかかわらず、小さな画面では高くなります

最小速度と最大速度をどうするか?小さい画面の作成者が、フリングジェスチャを報告する前に、75ピクセル/秒が完全な最小指速度であると判断したとします。小さいものはタッチエラーによる偶発的な投げ飛ばしになり、大きいものは何かを投げるにはあまりにも慎重なジェスチャーが必要になります。大型の電話の製造元が小型の電話と同じ完全な物理的動作(同じ指の速度)に一致させたい場合は、最小値を調整する必要があります速度を小さくします。より大きなデバイスのメーカーは、物理的特性のために、フリングを開始するために必要なピクセル/秒が少なくなります。画面の感度などの他の要因は、おそらくさまざまなメーカーを考慮に入れています。

ユーザーがスワイプジェスチャを行ったときに、異なるデバイスで同じエクスペリエンスを得るにはどうすればよいですか?

アニメーションを構成するには、ピクセル/秒で指定された速度を使用します。密度に依存しないパラメータの使用を避けるだけで、速度を正確に一致させることができるはずです。これは、最小または最大速度値とは何の関係もないことに注意してください。ただし、SWIPE_THRESHOLD_VELOCITYは、指定された密度に基づいて「生の」ピクセル値になるように計算する必要があります。これは、AndroidのLauncher2がホーム画面のアイテムフリングの密度に依存しないしきい値速度を計算する方法です。

int DENSITY_INDEPENDENT_THRESHOLD = 200;
Resources r = getResources();
float density = r.getDisplayMetrics().density;
SWIPE_THRESHOLD_VELOCITY = (int)(DENSITY_INDEPENDENT_THRESHOLD * density);

このしきい値は、上記の例の4 "電話と5"電話の両方で同じであることに注意してください。ここではしきい値についてのみ説明しているため、これは実際の速度には影響しません。しきい値を超えるには、4インチの電話よりも5インチの電話の方が20%速くスワイプする必要があります。 Androidランチャーはy方向に-1500のDENSITY_INDEPENDENT_THRESHOLDを使用しますが、200はアプリケーションに適しています。

最大速度データを使用して、すべてのAndroidデバイス間で均一なエクスペリエンスを作成できますか?

いいえ。最大速度は、正しくアニメーション化する必要のないエッジケースです。ゲームをプレイしていない限り、ユーザーが最大速度で何かを投げつけることはないと思います。ユーザーは、アニメーションが6000ピクセル/秒の速度で完全に一致するかどうかを気にしません。

TL; DR onFling引数からの生の速度を使用してアニメーションを構成し、速度を正確に一致させます。密度に依存しないパラメーターを使用してフリングアニメーションを構成することは避けてください。

7
Rich Ehmer

ベロシティは使用しないでください。使用するのは簡単ではありません。右にスワイプすると+の数字になり、左にスワイプすると-の数字になります。あなたはこれらをすることができます:

event1.getRawY() 
event2.getRawY()
event1.getRawX() 
event2.getRawX()

スワイプが左か右かを判断するには:

最初のイベントが2番目より多かった場合、人は左にスワイプしましたが、最後のイベントが最初のイベントよりx小さかった場合、人のスワイプは十分に遠く、それに反応したと言えます。右にスワイプした場合は逆にできます。また、onFlingは小さなタップを認識せず、タッチするだけなので、距離の速度や長さをまったく比較せずに逃げることができます。

0
superuser