onTouchEvent onClick onLongClick calls

2019-01-19 12:46发布

问题:

In our application we handle the events in button to record data.

So initially when i use setOnLongClickListener() and setOnClickListener() together with the same button, it work fine for us.

That means it will call both this listener base on the click and LongClick of the button. Now when i tried to use setOnTouchListener() with the same button together with setOnLongClickListener() and setOnClickListener() then only OnTouch event is working, rest onclick and onLongclick event doesnt work.

Can anyone tell me why this happen and if possible explain me with an example.

The code i use is..

Button btnAdd=new Button(this)

btnAdd.setOnLongClickListener(this);

btnAdd.setOnClickListener(this);

btnAdd.setOnTouchClickListener(this);

public void onClick(View v)
{
    //Statements;
}

public void onLongClick(View v)
{
    //Statements;
}

public boolean onTouch(View v, MotionEvent e) 
{
    switch (e.getAction())
    {
        case MotionEvent.ACTION_DOWN:
        {
            //store the X value when the user's finger was pressed down
            m_downXValue = e.getX();
            break;
        }   

        case MotionEvent.ACTION_UP:
        {
            //Get the X value when the user released his/her finger
            float currentX = e.getX();              
            //MotionEvent x=MotionEvent.obtain((long) m_downXValue,  SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 1, 1, 1, 1,0, 0, 0, 0, 0);

            // going forwards: pushing stuff to the left
            if (m_downXValue > currentX && currentX < 0)
            {                   
                ViewFlipper vf = (ViewFlipper) findViewById(R.id.flipview);
                vf.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.slide_left));


                vf.showNext();

            }

            // going backwards: pushing stuff to the right
            if (m_downXValue < currentX && currentX > 100)
            {                   
                ViewFlipper vf = (ViewFlipper) findViewById(R.id.flipview);                                     
                vf.setAnimation(AnimationUtils.loadAnimation(this, R.anim.slide_right));


                vf.showPrevious();

            }   

            if (m_downXValue == currentX)
            {                   
                onClick(v);
            }    

            break;
        }
    }
    return true;
}

回答1:

According to the doc Handling UI Events,

onLongClick() - This returns a boolean to indicate whether you have consumed the event and it should not be carried further. That is, return true to indicate that you have handled the event and it should stop here; return false if you have not handled it and/or the event should continue to any other on-click listeners.

And above all about onTouch:

onTouch() - This returns a boolean to indicate whether your listener consumes this event. The important thing is that this event can have multiple actions that follow each other. So, if you return false when the down action event is received, you indicate that you have not consumed the event and are also not interested in subsequent actions from this event. Thus, you will not be called for any other actions within the event, such as a finger gesture, or the eventual up action event.

Indeed, depending on the event, you have to return the right value.



回答2:

You have to return false instead of true in OnTouch(View v,MotionEvent event) function so that other listeners on the control remains active.



回答3:

Seems like you have reference problem. Try to set click, long click and touch listener like this:

btnAdd.setOnClickListener(new Button.OnClickListener(){
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
    }
});

btnAdd.setOnLongClickListener(new Button.OnLongClickListener(){
    @Override
    public boolean onLongClick(View v) {
        // TODO Auto-generated method stub
        return false;
    }
});

btnAdd.setOnTouchListener(new Button.OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        return false;
    }
});


回答4:

When you need both click and touch events on the same view, use a GestureDetector. It can detect long presses as well.



回答5:

I'm not sure this is what you're trying to achieve, as you set the onTouchListener for the button - but if what you want to achieve is a swipeable activity (e.g swipe the screen and the content of the screen changes) you could try letting your activity extend the class posted below and then implement the next() and previous() methods with what ever actions you want.

import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.GestureDetector.SimpleOnGestureListener;

public abstract class SwipeActivity extends Activity {
    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private GestureDetector gestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        gestureDetector = new GestureDetector( new SwipeDetector() );
    }

    private class SwipeDetector extends SimpleOnGestureListener {       
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {

            // Check movement along the Y-axis. If it exceeds SWIPE_MAX_OFF_PATH, then dismiss the swipe.
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;

            // Swipe from right to left.
            // The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE) and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
            if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                next();
                return true;
            }

            // Swipe from left to right.
            // The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE) and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
            if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                previous();
                return true;
            }

            return false;
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //TouchEvent dispatcher.
        if (gestureDetector != null) {
            if (gestureDetector.onTouchEvent(ev))
                //If the gestureDetector handles the event, a swipe has been executed and no more needs to be done.
                return true;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    protected abstract void previous();
    protected abstract void next();
}


回答6:

Here is how i solved a synchronisation with ontouch and onlongclick

Hope every body can figure out after looking at this code. What happens is whenever a long press happens the touchlistener is set for a none listener and when the view is touched again the none listener sets the touchlistener of the view to its previous listener

LinearLayout.LayoutParams longpressLP = new LinearLayout.LayoutParams(100,100);
    LinearLayout longpress = new LinearLayout(this);
    longpress.setBackgroundColor(Color.GREEN);
    //any layout you want to add your view in
    mainlayout.addView(longpress,longpressLP);



    final View.OnTouchListener buttontouch=new View.OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {
                    if(event.getAction()==MotionEvent.ACTION_DOWN)
                Toast.makeText(getApplicationContext(), "Touched Down", Toast.LENGTH_SHORT).show();
            else
                Toast.makeText(getApplicationContext(), "Touched", Toast.LENGTH_SHORT).show();
            return false;//IMPORTANT
        }
    };
    final View.OnTouchListener buttontouchnone=new View.OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {

            if(event.getAction()==MotionEvent.ACTION_DOWN)//IMPORTANT
            {
                v.setOnTouchListener(buttontouch);//IMPORTANT
                v.dispatchTouchEvent(event);//IMPORTANT
                Toast.makeText(getApplicationContext(), "ChangedListener", Toast.LENGTH_SHORT).show();
            }
            return false;//IMPORTANT
        }
    };
            //set listeners
    longpress.setOnTouchListener(buttontouch);
    longpress.setOnLongClickListener(new View.OnLongClickListener() {

        public boolean onLongClick(View v) {
            // TODO Auto-generated method stub
            Toast.makeText(getApplicationContext(), "LongClick", Toast.LENGTH_SHORT).show();
            v.setOnTouchListener(buttontouchnone);//IMPORTANT
            return true;//IMPORTANT
        }
    });