68

私は現在、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;
}

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

ACTION_DOWN で 0 に設定した新しい変数「mTouchDelay」を導入し、MOVE を増やし、MOVE で >= 3 の場合は「move」コードを実行します。しかし、これは本当に進むべき道ではないと感じています。

また、長押しを検出する方法もわかりません。犯人は本当に常にトリガーしているように見える MOVE です。

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

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

4

9 に答える 9

95

このコードは、クリックと移動 (ドラッグ、スクロール) を区別できます。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 で長押しを検出する

于 2013-05-10T15:43:59.323 に答える
22

Android ドキュメントから -

onLongClick()

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

onTouch()

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

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

于 2010-12-01T13:10:49.433 に答える
15

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

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

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);
于 2012-02-15T03:25:50.493 に答える
3

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

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

于 2012-07-02T04:57:21.850 に答える
3

クリック、長押し、スクロールを区別する必要がある場合は、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 (クリックを検出) を使用できるようになりました

于 2014-04-10T10:02:42.320 に答える
2

GestureDetectorを使用してAndroidおよび Androidスニペットでロングタッチ、ダブルタップ、スクロール、またはその他のタッチイベントを検出 し、 onSingleTapUp でタップロジックを実装し、onScrollイベントでロジックを移動するで説明されているように、GestureDetector.OnGestureListenerを実装する必要があると思います。

于 2012-09-24T17:46:08.467 に答える
0

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

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

于 2013-01-07T11:11:15.747 に答える
0

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;

ちょっとしたハックですが、うまくいきます。

于 2012-09-25T21:39:47.270 に答える