2011-10-28 14 views
16

私が取り組んでいるアプリケーションでは、特定のアクションが発生する前に、ユーザがある期間コンポーネントを保持することをユーザがクリックしなければならないという要件があります。LongClickイベントが速すぎます。それをトリガするのに必要なクリック時間をどのように増やすことができますか?

現在、OnLongClickListenerを使用してLongclickをリスンしていますが、OnLongClickイベントをトリガーするクリックの長さが短すぎます。

たとえば、400msのクリック後にLongClickイベントがトリガーされたとしますが、イベントがトリガーする前にユーザーが&を1200ms保持する必要があるとします。

LongClickイベントを構成してクリックを長くする方法はありますか?
また、長いクリックを聞くことができる別の構造がありますか?

答えて

17

onLongClickイベントでタイマーを変更することはできません。アンドロイド自体によって管理されます。

可能なことは.setOnTouchListener()を使用することです。

次に、MotionEventがACTION_DOWNのときに登録します。
変数の現在の時刻に注意してください。
次に、ACTION_UPを持つMotionEventが登録され、current_time-actionDown時間が> 1200ミリ秒に達したときに何かします。

ので、かなり

は:

Button button = new Button(); 
long then = 0; 
    button.setOnTouchListener(new OnTouchListener() { 

     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      if(event.getAction() == MotionEvent.ACTION_DOWN){ 
       then = (Long) System.currentTimeMillis(); 
      } 
      else if(event.getAction() == MotionEvent.ACTION_UP){ 
       if(((Long) System.currentTimeMillis() - then) > 1200){ 
        return true; 
       } 
      } 
      return false; 
     } 
    }) 
+0

これはほとんど私がそれを行うのに必要なことです。投稿されたアプローチは、ユーザーが指を離したときにのみコードを実行します。私は、ビジネスロジックを、ユーザーが押さなくても、遅延が上がるとすぐに実行したいと思います。 – ampersandre

+0

then then = getSystemTime()はコメントアウトされていますか? getSystemTime()メソッドも機能しません。あなたは: System.currentTimeMillis() –

+0

を確認しましたか?次に、intではなくlongとして定義します。次に、を使用します:then =(Long)System.currentTimeMillis();その差を見つけるときに、getSystemTime()の代わりにSystem.currentTimeMillis()を使用すると、もう一度長くキャストするようにしてください。 –

3

私は私の要件に合うように彼の答えを適応Rohan :)
の助けを借りて解決策を働きました。

ユーザーがボタンを押すと、スレッドが開始されます。スレッドは私の希望する遅延のためにスリープ状態になり、スリープ状態になると、必要なコードを実行します。ユーザーが離れると、スレッドは強制終了されます。これは、ユーザーがスレッドを起動する前にスレッドを中断し、アクションが発生しないため、必要な処理を実行します。

私はこの方法が好きです。なぜなら、遅れているとすぐにビジネスロジックを実行できるからです。これは、ユーザーに十分な時間をプッシュしたことを知らせるいくつかのフィードバックを与えることができるためです(電話は、例えば)。
このアプローチの欠点は、必要なアクションが実行されている間にユーザーがボタンを離し、すべてが完了する前にスレッドを強制終了するというリスクがあることです。私のビジネスロジックはほとんど役に立たないので、これは私の場合には大きな問題ではありません。他のクラスのイベントを処理するだけです。アクションが完全に完了しなかった場合は、ユーザーが再試行する必要はありません。

コードは少し時間がかかりますが、これがアプリケーションの共通機能であれば、簡単に再利用できます。ここでは、コードの例です:

protected class MyLongClickListener implements View.OnTouchListener { 
    private Thread longClickSensor; 

    public boolean onTouch(View view, MotionEvent event) { 
     // If the user is pressing down and there is no thread, make one and start it 
     if (event.getAction() == MotionEvent.ACTION_DOWN && longClickSensor == null) { 
      longClickSensor = new Thread(new MyDelayedAction()); 
      longClickSensor.start(); 
     } 
     // If the user has let go and there was a thread, stop it and forget about the thread 
     if (event.getAction() == MotionEvent.ACTION_UP && longClickSensor != null) { 
      longClickSensor.interrupt(); 
      longClickSensor = null; 
     } 
     return false; 
    } 

    private class MyDelayedAction implements Runnable { 
     private final long delayMs = 1200; 

     public void run() { 
      try { 
       Thread.sleep(delayMs); // Sleep for a while 
       doBusinessLogic();  // If the thread is still around after the sleep, do the work 
      } catch (InterruptedException e) { return; } 
     } 
     private void doBusinessLogic() { 
      // Make sure this logic is as quick as possible, or delegate it to some other class 
      // through Broadcasted Intents, because if the user lets go while the work is happenening, 
      // the thread will be interrupted. 
     } 
    } 
} 
+1

これは、ユーザーが2番目の指を使用すると乱雑になります。すでにスレッドが開始されているかどうか、または異なるピッカーIDを追跡する必要があるかどうかを確認する必要があります。 – xeed

2
final boolean[] isLongPress = {false}; 
final int duration = 3000; 
final Handler someHandler = new Handler(); 
    final Runnable someCall = new Runnable() { 
     @Override 
     public void run() { 
      if(isLongPress[0]) { 
       // your code goes here 
      } 
     } 
    }; 

    someButton.setOnTouchListener(new View.OnTouchListener() { 

     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      int eventAction = event.getAction(); 
      if(eventAction == MotionEvent.ACTION_DOWN){ 
       isLongPress[0] = true; 
       someHandler.postDelayed(someCall, duration); 
      } 
      else if (eventAction == MotionEvent.ACTION_UP) { 
       isLongPress[0] = false; 
       someHandler.removeCallbacks(someCall); 
      } 
      return false; 
     } 
    }); 
+0

'MotionEvent.ACTION_MOVE'が起動し、' removeCallbacks'が発生しました – UnLoCo

3

これは、私は、この動作を実現するために発見した最も簡単な方法です。それは現在受け入れられている答えよりも2つの利点があります。

  1. view.isPressedをチェックすることにより、我々はタッチイベントがビューを離れた場合onClickonLongClickトリガされていないことを確認してください。これは、デフォルトのonClickonLongClickのシステムの動作を模倣します。
  2. イベントにはタイミング情報がすでに格納されているため、開始時刻をACTION_DOWNに保存する必要はなく、ACTION_UPに現在時刻を計算する必要はありません。つまり、onTouch以外の1つの変数でイベントの開始時刻をトラッキングしていないため、複数のビューで同時に使用できます。

注:ViewConfiguration.getLongPressTimeout()がデフォルトであり、チェックを変更して任意の値を使用することができます。

注:通常、ビューをクリックできない場合は、view.isPressed()のチェックが機能するようにview.setClickable(true)に電話する必要があります。

@Override 
public boolean onTouch(View view, MotionEvent event) { 
    if (view.isPressed() && event.getAction() == MotionEvent.ACTION_UP) { 
     long eventDuration = event.getEventTime() - event.getDownTime(); 
     if (eventDuration > ViewConfiguration.getLongPressTimeout()) { 
      onLongClick(view); 
     } else { 
      onClick(view); 
     } 
    } 
    return false; 
} 

遅延期間は代わりに私のためだけでなく、その後ACTION_UPために、次の作業を待つので到達するとあなたは、@ampersandreのように、すぐにトリガするために長いクリックイベントをご希望の場合。

@Override 
public boolean onTouch(View view, MotionEvent event) { 
    if (event.getAction() == MotionEvent.ACTION_DOWN) { 
     view.setTag(true); 
    } else if (view.isPressed() && (boolean) view.getTag()) { 
     long eventDuration = event.getEventTime() - event.getDownTime(); 
     if (eventDuration > ViewConfiguration.getLongPressTimeout()) { 
      view.setTag(false); 
      onLongClick(view); 
     } else if (event.getAction() == MotionEvent.ACTION_UP) { 
      onClick(view); 
     } 
    } 
    return false; 
} 
+0

こんにちは!あなたの答えをありがとう、本当に私のために役立った。私はあなたの解決策(遅延期間が1に達すると直ちにトリガーする長いクリックイベント)に小さな問題が1つあります。継続時間>タイムアウトかどうかを確認するために連続してタッチイベントを持つ必要があります。したがって、Uが押されている間にボタン上で微妙な動きがない場合(イベントの移動...)、onLongClickトリガはタイムアウトより後に発生する可能性があります。何か提案はありますか?ありがとう! – Tom

0

私は、長いプレスイベントの仕組みを研究する簡単な解決策を見つけました。 ビューをクリックするたびに、タイプCheckForLongPressRunnableが遅延を伴ってキューに追加されます。遅延が終了すると、OnLongClickListenerが呼び出されます。遅延が終了する前に異なるイベントが存在する場合は、CheckForLongPress Runnableがキューから削除されます。

私はちょうど私が100にLONG_PRESS_MILLISを設定し、それが働いているOSの遅延

@Override public boolean postDelayed(Runnable action, long delayMillis) { 
    boolean isLongPress = action.getClass().getSimpleName().equals("CheckForLongPress"); 
    return super.postDelayed(action, isLongPress ? LONG_PRESS_MILLIS : delayMillis); 
} 

を変更するビューの公開方法postDelayed(Runnable action, long delayMillis)をオーバーライドします!

;)

関連する問題