29

I am working on application in which a user needs to press and hold a button for a long time.

How can I detect the moment that the user: finishes the press or moves their touch position?

Thanks

Tim
  • 4,414
  • 4
  • 35
  • 49
ItayM
  • 912
  • 2
  • 15
  • 36
  • You need to explain more why the user moving position is important. As for detecting end of a long press, just use setOnLongClickListener(). The onLongClick() method will be called automatically when the user releases the button. – Squonk May 31 '11 at 08:06
  • 5
    That's wrong - the onLongClick method is triggered as soon as a long click is detected -- ie: as soon as the timeout for a "long click" has occurred, NOT when the user releases the button. – John O'Connor May 24 '12 at 22:43

4 Answers4

67

I think your best bet is to use a combination of the onLongClickListener() and onTouchListener() for that button. You'll need to catch certain events on the touch listener since it will trigger for every touch event.

Try something like the following:

class Blah extends Activity {
     private Button mSpeak;
     private boolean isSpeakButtonLongPressed = false;

     @Override
     public void onCreate(Bundle icicle) {
          super.onCreate(icicle);
          setContentView(R.layout.blahlayout);
          Button mSpeak = (Button)findViewById(R.id.speakbutton);
          mSpeak.setOnLongClickListener(speakHoldListener);
          mSpeak.setOnTouchListener(speakTouchListener);
     }

     private View.OnLongClickListener speakHoldListener = new View.OnLongClickListener() {

          @Override
          public boolean onLongClick(View pView) {
               // Do something when your hold starts here.
               isSpeakButtonLongPressed = true;
               return true;
          }
     }

     private View.OnTouchListener speakTouchListener = new View.OnTouchListener() {

          @Override
          public boolean onTouch(View pView, MotionEvent pEvent) {
               pView.onTouchEvent(pEvent);
               // We're only interested in when the button is released.
               if (pEvent.getAction() == MotionEvent.ACTION_UP) {
                    // We're only interested in anything if our speak button is currently pressed.
                    if (isSpeakButtonLongPressed) {
                         // Do something when the button is released.
                         isSpeakButtonLongPressed = false;
                    }
               }
               return false;
          }
     }
}
John O'Connor
  • 5,244
  • 2
  • 24
  • 29
  • Thank you John, great solution. – alfdev Sep 14 '15 at 14:06
  • 4
    When I long pressed the button the action ran twice, I fixed it by returning true instead of false inside the onTouchListener. – DAVIDBALAS1 Jul 23 '16 at 13:41
  • This is perfectly what I wante! – X09 Aug 27 '16 at 10:54
  • How is this a great solution? User will have to stop holding the view for it to get its `pEvent.getAction() == MotionEvent.ACTION_UP` to be detected, whereas user expects to tap and hold and process start automatically, instead of tap and hold and release. – Bugs Happen Mar 11 '19 at 10:18
  • 1
    @BugsHappen - the asker specifically asked for that behavior: `How can I detect the moment that the user: finishes the press`. If you want a behavior to trigger once a long press is detected (even if the button is still pressed), you can use a longClickListener instead of using this technique. – John O'Connor Mar 13 '19 at 20:20
  • Wow! Thanks for the clear answer and the nice piece of code! – Murad Alm. Dec 29 '19 at 15:58
8

These answers are pretty complicated. onClick from an OnClickListener still gets called at the end of a long press if you return false from the OnLongClickListener. That's the easiest place to detect the end of a long press.

This is especially important to know because if you implement the onTouch route while returning false from onLongClick (the default AS gives you and often what you want), your onClick code may be called at the end of your long presses without you realizing it.

Here's an example based on capturing a photo or video:

private boolean takingVideo = false;

captureButton.setOnClickListener(v -> {
    // onClick gets called after normal click or long click
    if(takingVideo) {
        saveVideo();
    } else {
        takePhoto();
    }
});

captureButton.setOnLongClickListener(v -> {
    takeVideo();

    return false;
});

private void takePhoto() {
    // Save the photo
}

private void takeVideo() {
    takingVideo = true;
    // Start capturing video
}

private void saveVideo() {
    takingVideo = false;
    // Save the video
}

As you can see, the logic becomes very straight forward when you let Android propagate the end touch event to an OnClickListener.

Ben Kane
  • 9,331
  • 6
  • 36
  • 58
  • *"onClick gets called after normal click or long click"*. I'm unable to reproduce this. I never hear my clickListener on long click. – tir38 Mar 28 '20 at 14:53
  • @tir38 Did you make sure to return `false` from the `OnLongClickListener`? – Ben Kane Mar 28 '20 at 15:21
  • I’ll also note you used quotes but what I actually said is the onClick listener will get called at the end of the long click. I should have been more clear and maybe I should edit the answer. What I meant is onClick will be called when you lift your finger after long clicking. The take/save photo/video example demonstrates that – Ben Kane Mar 28 '20 at 15:26
1

I think you can use OnTouchListener for this.

Gordon
  • 312,688
  • 75
  • 539
  • 559
Sunil Kumar Sahoo
  • 53,011
  • 55
  • 178
  • 243
-2

I think the onFocusChanged-Listener can be used for this.

Lukas Knuth
  • 25,449
  • 15
  • 83
  • 111