开发者

MotionEvent Issues

开发者 https://www.devze.com 2023-04-08 01:28 出处:网络
I was wondering how to get accurate, get(x) and get(y) values for a MotionEvent? What is happening is that when I touch a specific area on the screen, I tell an action to happen.

I was wondering how to get accurate, get(x) and get(y) values for a MotionEvent? What is happening is that when I touch a specific area on the screen, I tell an action to happen. The problem is that once I touch the screen and take my finger off, it still thinks my finger is at the same location (since that was the last location I touched). So when I have more than one Down event (for multitouch) it throws everything off. Is there a way to reset the X and Y values so when I let off the screen, they go back to 0 or null (or whatever)?

Here is a video I just uploaded to explain it better, cause it is kind of confusing

http://www.youtube.com/watch?v=OHGj2z5SwQs

And here is the exact code I'm using

    int x = (int) e.getX();
    int y = (int) e.getY();
    int x2 = (int) e.getX(1);
    int y2 = (int) e.getY(1);


    boolean a1 = y > 0 && y < 200....etc        

    boolean a5 = etc... 

    switch (e.getActionMasked()) {
    case MotionEvent.ACTION_DOWN:
        x =  0;
        y = 0;          
        x2 = 0;
        y2 = 0;
                    ////I'm setting the x and y values to 0 as suggested

        text.setText("x:" + String.valueOf(x) + "y:" + String.valueOf(y));
                    //// This is so I can see the values on the screen
        if (a1 && a5){
            viewA1.setBackgroundColor(Color.GREEN);
            viewA5.setBackgroundColor(Color.GREEN);
        }
        if (a1) {

            viewA1.setBackgroundColor(Color.GREEN);
        }



        else if (a5) {
            viewA5.setBackgroundColor(Color.GREEN);

        }           



        break;

    case MotionEvent.ACTION_POINTER_1_DOWN:
        // /A Strummer
        x =  0;
        y = 0;

        x2 = 0;
        y2 = 0;

        text1.setText("x:" + String.valueOf(x2) + "y:" + String.valueOf(y2));
        if (a1 && a5){

            viewA1.setBackgroundColor(Color.GREEN);
            viewA5.setBackgroundColor(Color.GREEN);

        }
        if (a1) {

            viewA1.setBackgroundColor(Color.GREEN);
        }



        e开发者_Go百科lse if (a5) {

            viewA1.setBackgroundColor(Color.GREEN);

        }       
     /////I have pretty much the same method for ACTION_UP & ACTION_POINTER_UP; I set x & y to 0.

Please let me know if you can think of anything. I tried the methods you guys explained and it would seem like it would help, but it hasn't.


I don't have a tip but a working solution and some tips for multitouch starters. I never did that before so after seeing your question I was eager to now how multitouch works. And actually it's pretty tricky to get it done right. This is a great example for startes (view with four corners which are colored when one of the pointers is touching it - works with one up to five pointers / fingers). So I will explain it based on the working solution posted further below.

Basically it works like this: getPointerCount() is giving you the amount of currently touching pointers. getX(i) and getY(i) are giving you the corresponding coordinates. But this part is tricky: pointer 0, 1, 2 are touching, you lift 1 (second finger), and now you have 0, 1. This is the point where getPointerId(1) will return 2 because this is still your pointer 2 which is touching but it's now on position 1 instead 2. You have a single chance to react on that change, that's when ACTION_POINTER_UP is fired. On this action and on ACTION_POINTER_DOWN getActionIndex() will return the action pointer position of the pointer which was added or removed from pointer event list. Otherwise it's returning always 0 and that's something nobody tells you.

The conclusion is that you can't actually track which pointer is moving (that's why getActionIndex() is return 0 on move). That seems ridiculously logical because it would be stupid to fire 5 separate events for each finger. But while starting with multitouch that's a really non trivial fact ;-)

Here's the example. coordsX and coordsY will track the pointer coordinates and if position 2 contains valid coordinates, it means that this is your third finger which is still touching the screen whether you lifted the other fingers or not. This might not be relevant in this case but it's a fact which could still be useful in other multitouch implementations.

public class MultitouchView extends LinearLayout {

    // we have a maximum of 5 pointer
    // we will set Integer.MIN_VALUE if the pointer is not present
    private int [] coordsX = new int [5];
    private int [] coordsY = new int [5];

    // add 4 views with a certain gravity so they are placed in corners
    public MultitouchView(Context context, AttributeSet attrs) {
        super(context, attrs);

        // initialize as not present
        Arrays.fill(coordsX, Integer.MIN_VALUE);
        Arrays.fill(coordsY, Integer.MIN_VALUE);


        /* the layout is inflated from a XML file and is basically this one:
         * all subviews are matching / filling parent and have a weight of 1
         * <LinearLayout vertical>
         *   <LinearLayout horizontal>
         *     <View /><View />
         *   </LinearLayout>
         *   <LinearLayout horizontal>
         *     <View /><View />
         *   </LinearLayout>
         * </LinearLayout>
         */
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        if (e.getAction() == MotionEvent.ACTION_CANCEL) {
            // every touch is going to be canceled, clear everything
            Arrays.fill(coordsX, Integer.MIN_VALUE);
            Arrays.fill(coordsY, Integer.MIN_VALUE);
        } else {
            // track all touches
            for (int i = 0; i < e.getPointerCount(); i++) {
                int id = e.getPointerId(i);

                if (e.getActionIndex() == i
                        && (e.getActionMasked() == MotionEvent.ACTION_POINTER_UP
                        || e.getActionMasked() == MotionEvent.ACTION_UP)) {
                    // pointer with this id is about to leave, clear it
                    coordsX[id] = coordsY[id] = Integer.MIN_VALUE;
                } else {
                    // update all other pointer positions
                    coordsX[id] = (int) e.getX(i);
                    coordsY[id] = (int) e.getY(i);
                }
            }
        }

        int hw = getWidth() / 2;
        int hh = getHeight() / 2;

        // first no corner is touched
        boolean topLeft = false, topRight = false, bottomRight = false, bottomLeft = false;

        // check if any of the given pointer is touching a certain corner
        for (int i = 0; i < coordsX.length; i++) {
            // pointer is not active (anymore)
            if (coordsX[i] == Integer.MIN_VALUE || coordsY[i] == Integer.MIN_VALUE) {
                continue;
            }

            topLeft = topLeft || coordsX[i] < hw && coordsY[i] < hh;
            topRight = topRight || coordsX[i] > hw && coordsY[i] < hh;
            bottomRight = bottomRight || coordsX[i] > hw && coordsY[i] > hh;
            bottomLeft = bottomLeft || coordsX[i] < hw && coordsY[i] > hh;
        }

        // set the result we have now to the views represnting the corners
        ((ViewGroup) getChildAt(0)).getChildAt(0).setBackgroundColor(topLeft ? 0xffffff00 : 0x0);
        ((ViewGroup) getChildAt(0)).getChildAt(1).setBackgroundColor(topRight ? 0xffff0000 : 0x0);
        ((ViewGroup) getChildAt(1)).getChildAt(0).setBackgroundColor(bottomLeft ? 0xff00ff00 : 0x0);
        ((ViewGroup) getChildAt(1)).getChildAt(1).setBackgroundColor(bottomRight ? 0xff0000ff : 0x0);

        return true;
    }
}


You should use ‘motionEvent.getPoinerCount()‘ to check the number of touch points.

0

精彩评论

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

关注公众号