OnTouch MotionEvent Action Move not triggering

2019-07-11 07:44发布

问题:

I'm trying to get X, Y coordinates while I'm dragging my button, but for some reason, the code bellow attached on touch listener triggers only twice instead of constant update while dragging, even with trothing I will be satisfied in order to improve performance, but as I said, onTouch method triggered just on action down, and one more time later.

This is my code:

final Button dragBtn = (Button) findViewById(R.id.MyTestButton);

    dragBtn.setOnTouchListener(new View.OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent me) {
        // TODO Auto-generated method stub
        ClipData data = ClipData.newPlainText("", "");
        View.DragShadowBuilder shadow = new View.DragShadowBuilder(dragBtn);
        v.startDrag(data, shadow, null, 0);
        int action = me.getAction();


        if (action==MotionEvent.ACTION_DOWN) {

            Log.i("TEST", "ACTION_DOWN");
            return true;
        }


        if (action==MotionEvent.ACTION_MOVE){
            Log.i("TEST", "ACTION_MOVE");

            float x = me.getX();
            float y = me.getY();

            //TODO: Rest of my code here.

            return true;
        }

        if (action==MotionEvent.ACTION_UP){

            Log.i("TEST", "ACTION_UP");
            return true;
        }

        Log.i("TEST", "UKNOWN ACTION");
        return true;
    }
});

And in log I have just:

ACTION_DOWN
WindowManager﹕ Drag already in progress
UKNOWN ACTION

回答1:

You want to capture the X and Y coordinate data in your OnDragListener not your OnTouchListener. For the whole time that you are dragging the object around the screen, Android interprets that as one single ACTION_MOVE event, hence you only get data once from that. Place the following code inside your custom OnDragListener class:

@Override
public boolean onDrag(View v, DragEvent event) {
    int action = event.getAction();
    float xCoord;
    float yCoord;
    if(action == DragEvent.ACTION_DRAG_LOCATION) {
        xCoord = event.getX();
        yCoord = event.getY();
    }
    return event.getResult();       //returns true for valid drop or false for invalid drop
}

Somewhere else in your custom OnDragListener class, you will have to do something with that xCoord and yCoord data. For example in my app, I have a TextView on my "debug" version of the app where I display the xCoord and yCoord data. I execute the TextView.setText() method right after I get those two values in my if(action == DragEvent.ACTION_DRAG_LOCATION){... section.

Hope this helps.



回答2:

MotionEvent.getAction encodes the action type as well as additional pointer information (for multi-touch handling). You want MotionEvent.getActionMasked to get just the action part.

Edit: also, per discussion below there's some issue with startDragging.



回答3:

Once the system has the drag shadow, it begins the drag and drop operation by sending drag events to all the View objects in your application that are currently visible. It does this either by calling the View object's drag listener (an implementation of onDrag() or by calling the View object's onDragEvent() method. Both are passed a DragEvent object that has a getAction() value of ACTION_DRAG_STARTED



回答4:

finaly your code should be like this.

int basex;
int basey;
RelativeLayout.LayoutParams layoutParams;
RelativeLayout layBg;


....................

dragBtn.setOnTouchListener(new View.OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent me) {
        // TODO Auto-generated method stub


 layoutParams = (RelativeLayout.LayoutParams) dragBtn.getLayoutParams();

        switch (me.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        basex = ((int) (me.getRawX() - layoutParams.leftMargin));
                        basey = ((int) (me.getRawY() - layoutParams.topMargin));
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int i = (int) event.getRawX();
                        int j = (int) event.getRawY();
                        layBg = ((RelativeLayout) dragBtn.getParent());
                        if ((i - basex > -(dragBtn.getWidth() * 2 / 3))
                                && (i - basex < layBg.getWidth() - dragBtn.getWidth() / 3)) {
                            layoutParams.leftMargin = (i - basex);
                        }
                        if ((j - basey > -(dragBtn.getHeight() * 2 / 3))
                                && (j - basey < layBg.getHeight() - dragBtn.getHeight() / 3)) {
                            layoutParams.topMargin = (j - basey);
                        }
                        layoutParams.rightMargin = -1000;
                        layoutParams.bottomMargin = -1000;
                        dragBtn.setLayoutParams(layoutParams);
                        break;

                    }

                    return true;
    }
});