Single method to implement onTouchListener() for multiple buttons
Asked Answered
S

9

8

I am trying to see if there is a way to create a single method to implement a touch listener for multiple buttons, seeing as I have quite a few buttons that do almost exactly the same thing. The only difference in what they do is the message that they would send through my sendMessage() method, and how long the button needs to be held down for the message to be sent. If there is a way to do it, what might that be? And also, why wouldn't something like this work?

//Within onCreate Method...
Button mButton = (Button) findViewbyId(R.id.three_sec_button);
mButton = addTouchTimer(mButton, 3, 3);

Calls -

private Button addTouchTimer(Button button, final int sec, final int messageNum){
        button.setOnTouchListener(new View.OnTouchListener() {
            boolean longEnough = false;
            long realTimeLeft = sec * 1000;
            @Override
            // This will make it so that a message is only sent if the button is held down for 3 seconds
            // Otherwise it won't send. It is sent during the hold down process, releasing it returns a false
            // value and no message is sent.
            public boolean onTouch(View arg0, MotionEvent arg1) {
                Log.d("Button", "Touchy Touchy!");
                if(arg1.getAction() == MotionEvent.ACTION_DOWN){
                    buttonPressTime = new CountDownTimer(realTimeLeft, 1000){
                        @Override
                        public void onTick(long millisUntilDone){
                                realTimeLeft = millisUntilDone;
                        }

                        @Override
                        public void onFinish() {  
                            long timeLeft = realTimeLeft;
                            long currTime = System.currentTimeMillis();
                            long realFinishTime = currTime + timeLeft;
                                while(currTime < realFinishTime){
                                    currTime = System.currentTimeMillis();
                                }
                            longEnough = true;
                            sendEmergencyMessage(longEnough, messageNum);
                        }
                    }.start();
                }
                else if(arg1.getAction() == MotionEvent.ACTION_UP){
                    buttonPressTime.cancel();
                    sendMessage(longEnough, messageNum);
                }
                return longEnough;
            }           
        });

        return button;
    }

It just seems that for efficiency's sake there has to be a better way of doing it than implementing individual listeners for each button. As a note, sendMessage() has a Log call in it that utilizes the boolean value, I want to see what it is set as when it is passed. That is the only reason it is called during the release of the button.

Scattering answered 25/7, 2013 at 16:53 Comment(0)
C
20

Yes you are right, there is a better way. A single TouchListener that handles everything, determining which button it is via the id.

void intialization(){
     Button m1, m2, m3, m4;
     ... //do initialization stuff
     m1.setId(1);
     m2.setId(2);
     m3.setId(3);
     m4.setId(4);
     MyTouchListener touchListener = new MyTouchListener();
     m1.setOnTouchListener(touchListener);
     m2.setOnTouchListener(touchListener);
     m3.setOnTouchListener(touchListener);
     m4.setOnTouchListener(touchListener);
 }

public class MyTouchListener implements OnTouchListener {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch(v.getId()){
            case 1:
                //do stuff for button 1
                break;
            case 2:
                //do stuff for button 2
                break;
            case 3:
                //do stuff for button 3
                break;
            case 4:
                //do stuff for button 4
                break;
        }
        return true;
    }

}

And that's how you'd do it! A numerical approach for the id's is very helpful in this case. Another approach is to have your activity implement the OnTouchListener in your activity, and then your code would be even simpler.

public class MyActivity extends Activity implements OnTouchListener {

    void initialization(){
        Button m1, m2, m3, m4;
        ... //do initialization stuff
        m1.setId(1);
        m2.setId(2);
        m3.setId(3);
        m4.setId(4);
        m1.setOnTouchListener(this);
        m2.setOnTouchListener(this);
        m3.setOnTouchListener(this);
        m4.setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch(v.getId()){
            case 1:
                //do stuff for button 1
                break;
            case 2:
                //do stuff for button 2
                break;
            case 3:
                //do stuff for button 3
                break;
            case 4:
                //do stuff for button 4
                break;
        }
        return true;
    }

}

Note: This approach also will also work for OnClickListener, OnCheckedChangeListener, or any other listener that you would set on an Android view.

Coordination answered 25/7, 2013 at 17:3 Comment(7)
Man, I may have been sitting by the computer too long. Should have known this one. However, question. Do you mean I should implement a new class called MyTouchListener or did you just add that arbitrarily? Can't I just do what was said below and implement it in my main class and then call the onTouch method like "m1.setOnTouchListener(onTouch());Scattering
You can make your main activity implement touch listener. And can see my answer for reference.Recommend
@Scattering : If we have solved your problem, Please accept one of them as answer. It will be useful for others.Recommend
@Scattering You can just call it anything you like. The important part is that it implements OnTouchListenerCoordination
I am working on getting it to work, I will accept one when I get one to work for me :)Scattering
why does the flow goes to rest of the case statement if "break" is missing? Shouldn't it break out of case statement anyway?Derma
@ParvaThakkar because that's how case statements work, it's just the way they were designed. It can be a helpful feature in certain situations.Coordination
C
7

With ButterKnife it would be like this. (in my case ImageView as buttons)

@OnTouch({R.id.Button1, R.id.Button2, R.id.Button3})
public boolean buttonsTouched(ImageView button, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            --(Your ACTION on Pressed)--
            return true;
        case MotionEvent.ACTION_UP:
            --(Your ACTION on Release)--
            return true;
    }
    return true;
}
Circumscissile answered 6/4, 2017 at 14:32 Comment(0)
R
4

Yeah, there is a better approach of doing the same.
1) Make your class implement OnTouchListener.
2) Add this listener to every button that should handle touch event. Like this:

button1.setOnTouchListener(this);

3) And in this public boolean onTouch(View arg0, MotionEvent arg1) {});

method you can use switch case on the view that was touched . The first argument i.e. arg0 is the view the touch event has been dispatched to. In your case it will be different buttons. Something like this:

public boolean onTouch(View arg0, MotionEvent arg1) {
    if (arg1.getAction() == MotionEvent.ACTION_DOWN) {
        switch (arg0.getId()) {
        case R.id.button1: // Id of the button
            // Your code goes here
            break;

        case R.id.button2: // Id of the button
            // Your code goes here
            break;

        default:
            break;
        }
    }
    return true;
}
Recommend answered 25/7, 2013 at 17:6 Comment(2)
This also works, I mixed and matched yours with the above answer, specifically utilizing setId() getId(). His was a bit earlier so I gave him the check, but this also works well. If I could I would give you both checks of approval.Scattering
That's completely fine :)Recommend
G
1
OnTouchListener mOnTouchListener = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // Code goes here
    return true;
    }
};

button1.setOnTouchListener(mOnTouchListener);
button2.setOnTouchListener(mOnTouchListener);
Gotcher answered 25/7, 2013 at 18:9 Comment(0)
S
1

I merge two answer, this is my code

public class MyActivity extends Activity implements OnTouchListener {
Button mGreen, mRed;

void initialization() {

    ... //do initialization stuff

    mGreen.setOnTouchListener(this);
    mRed.setOnTouchListener(this);
}

@Override
public boolean onTouch(View v, MotionEvent event) {


    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            actionDown();
            break;
        case MotionEvent.ACTION_UP:
            actionUp();
            break;

        case MotionEvent.ACTION_POINTER_DOWN:
            break;

        case MotionEvent.ACTION_POINTER_UP:
            break;

        case MotionEvent.ACTION_MOVE:
            actionMove();
            break;
    }

    return true;
}

public void actionDown() {
    switch (view.getId()) {
        case R.id.button_green:
            //todo
            break;

        case R.id.button_red:
            //todo
            break;
    }
}

public void actionUp() {
    switch (view.getId()) {
        case R.id.button_green:
            //todo
            break;


        case R.id.button_red:
            //todo
            break;
    }
}

public void actionMove() {
    switch (view.getId()) {
        case R.id.button_green:
            // todo
            break;

        case R.id.button_red:
            // todo
            break;
    }

}}

I hope that this code will help someone

Saros answered 2/2, 2016 at 16:18 Comment(0)
C
0

Why don't you use butterknife?

@Nullable @OnClick({R.id.btn1, R.id.btn2,R.id.btn3, R.id.btn4})
public void doStuff(Button button) {}
Cool answered 11/4, 2016 at 12:26 Comment(2)
It is not onTouchEvent listenerFonseca
@OnTouch(R.id.view_thing) public boolean onTouch(View view, MotionEvent motionEvent) { }Bogoch
J
0
@Override
        public boolean onTouch(View view, MotionEvent motionEvent)
        {
            switch (motionEvent.getAction() & MotionEvent.ACTION_MASK)
            {
                case MotionEvent.ACTION_DOWN:
                    shouldClick = true;
                    .
                    .
                    break;
                case MotionEvent.ACTION_UP:
                    if (shouldClick)
                        view.performClick();
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    break;
                case MotionEvent.ACTION_POINTER_UP:
                    break;
                case MotionEvent.ACTION_MOVE:
                    //Do your stuff
                    shouldClick = false;
                    break;
            }
            rootLayout.invalidate();
            return true;
        }
Johannisberger answered 9/9, 2018 at 19:7 Comment(0)
C
0

In my case what i needed is similar to answers above, but my purpose is different...

I wanted to hide my keyboard whenever you touch the screen, regardless UP, or DOWN

   /**
     * Hide keyboard on touching the screen
     * <a href="https://mcmap.net/q/1240392/-single-method-to-implement-ontouchlistener-for-multiple-buttons">how to hide on touch</a>
     */
    @OnTouch(R.id.scroll_sign_up_step2_view)
    public boolean hideKeyBoardOnTouch() {
        hideKeyboard();
        return true;
    }
Charteris answered 11/2, 2019 at 8:42 Comment(0)
C
0

In Kotlin you can create object class with onTouch variable and then use it anywhere you want.

In Listeners.kt

object Listeners {
    val onTouch = View.OnTouchListener { v: View, event: MotionEvent ->
        //Do anything with view here and check event type
        return@OnTouchListener false
    }
}

And then in your activities


button.setOnTouchListener(Listeners.onTouch)

Clobber answered 19/2, 2021 at 8:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.