开发者

How to get a continuous Touch Event?

My class extends View and I need to get continuous touch events on it.

If I use:

public boolean onTouchEvent(MotionEvent me) {

    if(me.getAction()==MotionEvent.ACTION_DOWN) {
    开发者_运维知识库    myAction();
    }
    return true;
}

... the touch event is captured once.

What if I need to get continuous touches without moving the finger? Please, tell me I don't need to use threads or timers. My app is already too much heavy.

Thanks.


Use if(me.getAction() == MotionEvent.ACTION_MOVE). It's impossible to keep a finger 100% completely still on the screen so Action_Move will get called every time the finger moves, even if it's only a pixel or two.

You could also listen for me.getAction() == MotionEvent.ACTION_UP - until that happens, the user must still have their finger on the screen.


You need to set this properties for the element android:focusable="true" android:clickable="true" if not, just produce the down action.


Her is the simple code snippet which shows that how you can handle the continues touch event. When you touch the device and hold the touch and move your finder, the Touch Move action performed.

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();
    if(isTsunami){
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // Write your code to perform an action on down
            break;
        case MotionEvent.ACTION_MOVE:
            // Write your code to perform an action on contineus touch move
            break;
        case MotionEvent.ACTION_UP:
            // Write your code to perform an action on touch up
            break;
    }
    }
    return true;
}


Try this. It works to me:

public static OnTouchListener loadContainerOnTouchListener() {
    OnTouchListener listener = new OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        LinearLayout layout = (LinearLayout)v;
        for(int i =0; i< layout.getChildCount(); i++)
        {
            View view = layout.getChildAt(i);
            Rect outRect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
            if(outRect.contains((int)event.getX(), (int)event.getY()))
            {
                Log.d(this.getClass().getName(), String.format("Over view.id[%d]", view.getId()));
            }
        }

    }

Remember: the listener you´ll set must be a container layout (Grid, Relative, Linear).

LinearLayout layout = findViewById(R.id.yourlayoutid);
layout.setOnTouchListener(HelperClass.loadContainerOnTouchListener());


This might help,

requestDisallowInterceptTouchEvent(true);

on the parent view, like this -

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            view.getParent().requestDisallowInterceptTouchEvent(true);
            switch(motionEvent.getAction()){
            }

            return false; 

         }


I was making a game with a custom view used as a thumb control. . . here is what I did

float x = 0, y = 0;

@Override
public boolean onTouchEvent(MotionEvent event) {
    x = event.getX();
    y = event.getY();

    // handle touch events with 
    switch( event.getActionMasked() ) {
        case MotionEvent.ACTION_DOWN :
            if(cont)
            {
                // remove any previous callbacks
                removeCallbacks(contin);

                // post new runnable
                postDelayed(contin, 10);
            }
            invalidate();
            return true;
        case MotionEvent.ACTION_MOVE :
            if(!cont && thumbing != null)
            {
                //  do non-continuous operations here
            }
            invalidate();       
            return true;
        case MotionEvent.ACTION_UP :

            // set runnable condition to false
            x = 0;

            // remove the callbacks to the thread
            removeCallbacks(contin);
            invalidate();
            return true;
        default :
            return super.onTouchEvent(event);
    }
}

public boolean cont = false;

// sets input to continuous
public void set_continuous(boolean b) { cont = b; }


public Runnable contin = new Runnable()
{

    @Override
    public void run() {
        if(x != 0)
        {
            //  do continuous operations here
            postDelayed(this, 10);
        }
    }

};

A quick note however, make sure in your main activity that is calling this view removes the callbacks manually via the onPause method as follows

@Override
protected void onPause() {
    if(left.cont) left.removeCallbacks(left.contin);
    if(right.cont) right.removeCallbacks(left.contin); 
    super.onPause();
}

That way if you pause and come back touch events aren't being handled twice and the view is free from it's thread's overhead.

** tested on Samsung Galaxy S3 with hardware acceleration on **


All these answer are partially correct but they do not resolve in the right way the problem.

First of all, for everyone out there that decide to track when the event is ACTION_MOVE. Well that works only guess when? When user move his finger, so could if you decide to implement a custom thumb control is okay but for a normal custom button that's not the case.

Second, using a flag inside ACTION_DOWN and check it in ACTION_UP seems the logic way to do it, but as Clusterfux find out if you implement a while(!up_flag) logic you get stuck into troubles ;)

So the proper way to do it is mentioned here:

Continuous "Action_DOWN" in Android

Just keep in mind that if the logic you're going to write during the continuous press has to modify the UI in some way, you have to do it from the main thread in all the other cases it's better use another thread.


You can use the below code snippet as a reference in which I used the background to detect if the screen is held or not...

Main_Layout.setOnTouchListener(new View.OnTouchListener() {
        @SuppressLint("ResourceAsColor")
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            switch (event.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    Main_Layout.setBackgroundColor(R.color.green);
                    event.setAction(MotionEvent.ACTION_DOWN);
                    break;
                default:
                    Main_Layout.setBackgroundColor(R.color.blue);
                    break;

            }
            return false;
        }
    });
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜