web-dev-qa-db-ja.com

タッチプレスvs長押しvs動きを検出しますか?

現在、Androidプログラミングをいじっていますが、通常のタッチプレス(画面を押してすぐに離す)、長押し(画面に触れて、指をその上に保持します)、動き(画面上でドラッグ)。

私がやりたかったのは、画面上にドラッグできる(円の)画像を持っていることです。次に、1回押すと(短押し/通常押し)、トーストに基本的な情報が表示されます。長く押すと、リストを含むAlertDialogが表示され、別の画像(円、長方形、または三角形)を選択します。

イベントを検出し、onDrawで画像を描画するために、独自のOnTouchListenerでカスタムビューを作成しました。 OnTouchListener.onTouchは次のようになります。

// has a touch press started?
private boolean touchStarted = false;
// co-ordinates of image
private int x, y;

public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        touchStarted = true;
    }
    else if (action == MotionEvent.ACTION_MOVE) {
        // movement: cancel the touch press
        touchStarted = false;

        x = event.getX();
        y = event.getY();

        invalidate(); // request draw
    }
    else if (action == MotionEvent.ACTION_UP) {
        if (touchStarted) {
            // touch press complete, show toast
            Toast.makeText(v.getContext(), "Coords: " + x + ", " + y, 1000).show();
        }
    }

    return true;
}

問題は、画面をさりげなくタッチすると、わずかな動きも検出し、タッチプレスをキャンセルして代わりに画像内を移動するため、プレスが期待どおりに機能しないことです。

私はこれを少し「ハッキング」して、新しい変数「mTouchDelay」を導入し、ACTION_DOWNで0に設定し、MOVEを増やし、MOVEで3以上の場合、「move」コードを実行します。しかし、私はこれが本当に進むべき道ではないと感じています。

また、長押しを検出する方法も見つけていません。犯人は、実際に常にトリガーされると思われるMOVEです。

おおよその例については、Androidアプリケーション「DailyStrip」を参照してください。漫画ストリップの画像を表示します。画面に対して大きすぎる場合はドラッグできます。タップできます一部のコントロールがポップアップするために一度押し、オプションメニューのために長押しします。

PS。私の携帯電話は1.5でしか動作しないため、Android 1.5で動作するようにしようとしています。

64
pbean

このコードは、クリックと移動(ドラッグ、スクロール)を区別できます。 onTouchEventでフラグisOnClickを設定し、最初のX、YはACTION_DOWNで調整します。 ACTION_MOVEのフラグをクリアします(THRESHOLD constで解決できる意図しない動きがしばしば検出されることに注意してください)。

private float mDownX;
private float mDownY;
private final float SCROLL_THRESHOLD = 10;
private boolean isOnClick;

@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            mDownX = ev.getX();
            mDownY = ev.getY();
            isOnClick = true;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (isOnClick) {
                Log.i(LOG_TAG, "onClick ");
                //TODO onClick code
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (isOnClick && (Math.abs(mDownX - ev.getX()) > SCROLL_THRESHOLD || Math.abs(mDownY - ev.getY()) > SCROLL_THRESHOLD)) {
                Log.i(LOG_TAG, "movement detected");
                isOnClick = false;
            }
            break;
        default:
            break;
    }
    return true;
}

上記で提案したLongPressの場合、GestureDetectorが最適です。このQ&Aを確認してください。

Androidで長押しを検出

92
MSquare

Android Docs-

onLongClick()

View.OnLongClickListenerから。これは、ユーザーがアイテムをタッチして保持する(タッチモードの場合)か、ナビゲーションキーまたはトラックボールでアイテムにフォーカスし、適切な「Enter」キーを押して保持するか、トラックボールを押して保持するときに呼び出されます( 1秒間)。

onTouch()

View.OnTouchListenerから。これは、ユーザーがタッチイベントとして修飾されたアクションを実行するときに呼び出されます。これには、画面上の(アイテムの境界内での)プレス、リリース、または移動ジェスチャーが含まれます。

「タッチしても移動は発生します」に関しては、デルタを設定し、移動コードを開始する前に、少なくともデルタだけビューが移動されていることを確認します。そうでない場合は、タッチコードを開始します。

20
Jason L.

私はこれを多くの実験の後に発見しました。

アクティビティの初期化:

setOnLongClickListener(new View.OnLongClickListener() {
  public boolean onLongClick(View view) {
    activity.openContextMenu(view);  
    return true;  // avoid extra click events
  }
});
setOnTouch(new View.OnTouchListener(){
  public boolean onTouch(View v, MotionEvent e){
    switch(e.getAction & MotionEvent.ACTION_MASK){
      // do drag/gesture processing. 
    }
    // you MUST return false for ACTION_DOWN and ACTION_UP, for long click to work
    // you can return true for ACTION_MOVEs that you consume. 
    // DOWN/UP are needed by the long click timer.
    // if you want, you can consume the UP if you have made a drag - so that after 
    // a long drag, no long-click is generated.
    return false;
  }
});
setLongClickable(true);
15
Sanjay Manohar

クリック、ロングプレス、スクロールを区別する必要がある場合は、GestureDetectorを使用します

アクティビティはGestureDetector.OnGestureListener

次に、onCreateで検出器を作成します

mDetector = new GestureDetectorCompat(getActivity().getApplicationContext(),this);

次に、オプションでビュー(たとえば、webview)でsetOnTouchListenerを設定します。

onTouch(View v, MotionEvent event) {
return mDetector.onTouchEvent(event);
}

onScroll、onFling、showPress(長押しを検出)またはonSingleTapUp(クリックを検出)をオーバーライドできます

3
voytez

私は同様のソリューションを探していましたが、これは私が提案するものです。 OnTouchメソッドで、MotionEvent.ACTION_DOWNイベントの時間を記録してから、MotionEvent.ACTION_UPの時間を再度記録します。このようにして、独自のしきい値を設定することもできます。数回実験した後、単純なタッチを記録する必要があるミリ秒単位の最大時間を知ることができ、これを移動または他の方法で自由に使用できます。

これが役に立てば幸いです。別の方法を使用して問題を解決した場合はコメントしてください。

3
rajankz

GestureDetectorを使用してAndroidのロングタッチ、ダブルタップ、スクロールまたはその他のタッチイベントを検出する および androidsnippets の説明に従ってGestureDetector.OnGestureListenerを実装してから、 onSingleTapUpおよびonScrollイベントのロジックの移動

2
Lord_JABA

オーバーレイクラスでontouchイベントが必要でした。これを確認してください、それは私を助けました

http://mirnauman.wordpress.com/2012/04/16/Android-google-maps-tutorial-part-6-getting-the-location-that-is-touched/

0
Nakul Sudhakar

GestureDetector.SimpleOnGestureListenerには、これら3つの場合に役立つメソッドがあります。

   GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {

        //for single click event.
        @Override
        public boolean onSingleTapUp(MotionEvent motionEvent) {
            return true;
        }

        //for detecting a press event. Code for drag can be added here.
        @Override
        public void onShowPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData clipData = ClipData.newPlainText("..", "...");
            clipboardManager.setPrimaryClip(clipData);

            ConceptDragShadowBuilder dragShadowBuilder = new CustomDragShadowBuilder(child);
            // drag child view.
            child.startDrag(clipData, dragShadowBuilder, child, 0);
        }

        //for detecting longpress event
        @Override
        public void onLongPress(MotionEvent e) {
            super.onLongPress(e);
        }
    });
0
Subhanandh

Longclickがクリックイベントで終了しないようにした後、この混乱に対処していました。

これが私がしたことです。

public boolean onLongClick(View arg0) {
    Toast.makeText(getContext(), "long click", Toast.LENGTH_SHORT).show();
    longClicked = true;
    return false;
}

public void onClick(View arg0) {
    if(!longClicked){
        Toast.makeText(getContext(), "click", Toast.LENGTH_SHORT).show();
    }
    longClick = false; // sets the clickability enabled
}

boolean longClicked = false;

ちょっとしたハックですが、動作します。

0
Chris Sullivan