【问题标题】:How to detect single touch as well as multi-touch in onTouchEvent()如何在 onTouchEvent() 中检测单点触控和多点触控
【发布时间】:2012-04-12 05:01:42
【问题描述】:

我使用以下代码来检测单指触摸和双指触摸。代码检测到双指触摸(count==2 时)。

我还需要在单点触摸时执行一些操作。如果我用一根手指触摸屏幕,则不会用于其他部分。我在这段代码中做错了什么?

@Override
public boolean onTouchEvent(MotionEvent event) {
    int action = event.getAction() & MotionEvent.ACTION_MASK;
    switch (action) {
        case MotionEvent.ACTION_POINTER_UP: {
            int count = event.getPointerCount();
            Log.v("count >>", count + "");
            if (count == 2) {
                // some action
            } else {
                Log.v("count not equal to 2", "not 2");
            }
            break;
        }
    }
    return true;
}

更新:

我在Activity 中使用了这段代码。我需要检测单点触控、多点触控。

在我的活动中,我有两张图片,一张在左边,一张在右边。如果我单击图像,则必须执行一些过程。如果我用两根手指,我需要根据scale-factor 重新调整图像大小。

这是我用过的代码:

更新:

package com.pinch.detect;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.FloatMath;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class PinchDetectorActivity extends Activity {
    TextView textGestureAction;
    ImageView img1, img2;
    static Bitmap bm, bm1;

    boolean multiTouch = false;
    Context context;
    float scaleFactor = 0.0f;
    float lastscale;
    int scr_width, scr_height;
    Display display;
    private ScaleGestureDetector scaleGestureDetector;

    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textGestureAction = (TextView) findViewById(R.id.GestureAction);
        img1 = (ImageView) findViewById(R.id.img_left);
        img2 = (ImageView) findViewById(R.id.img_right);
        display = getWindowManager().getDefaultDisplay();

        scr_width = display.getWidth();
        scr_height = display.getHeight();
        Log.v("width >>", Integer.toString(scr_width));
        Log.v("height >>", Integer.toString(scr_height));

        bm = BitmapFactory.decodeResource(this.getResources(),
                R.drawable.fiction1);
        img1.setImageBitmap(bm);
        bm1 = BitmapFactory.decodeResource(this.getResources(),
                R.drawable.fiction2);
        img2.setImageBitmap(bm1);
        img1.setScaleType(ImageView.ScaleType.FIT_START);
        img2.setScaleType(ImageView.ScaleType.FIT_END);

        scaleGestureDetector = new ScaleGestureDetector(this,
                new MySimpleOnScaleGestureListener());



        img1.setOnTouchListener(new OnTouchListener(){

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

        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        scaleGestureDetector.onTouchEvent(event);
        int index = event.getActionIndex();
        Log.v("Index value ",index+"");
        int action = event.getAction();

        if (index == 1) {
            multiTouch = true;
            System.out.println("mutli1");
        } else if (multiTouch == false) {
            System.out.println("single1");
            img1.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Log.v("clicked image1","img1>>>");
                }
            });
            img2.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) { // TODO Auto-generated method
                    Log.v("clicked image2","img2>>>");
                }
            });
        }

         else if (action == MotionEvent.ACTION_MOVE && multiTouch) {
            System.out.println("mutli2");


            if (scaleFactor > 1) {

                Bitmap resizedbitmap = Bitmap.createScaledBitmap(bm,
                        scr_width / 2, scr_height, true);
                img1.setImageBitmap(resizedbitmap);
                Bitmap resizedbitmap1 = Bitmap.createScaledBitmap(bm1,
                        scr_width / 2, scr_height, true);
                img2.setImageBitmap(resizedbitmap1);
                Log.v("width >>", Integer.toString(scr_width));
                Log.v("height >>", Integer.toString(scr_height));

            } else if(scaleFactor<1){

                Log.v("width >>", Integer.toString(scr_width));
                Log.v("height >>", Integer.toString(scr_height));
                if (scr_width >= 640) {
                    Bitmap resizedbitmap = Bitmap.createScaledBitmap(bm,
                            scr_height + 90, scr_height, true);

                    img1.setImageBitmap(resizedbitmap);

                    Bitmap resizedbitmap1 = Bitmap.createScaledBitmap(bm1,
                            scr_height + 90, scr_height, true);

                    img2.setImageBitmap(resizedbitmap1);
                } else {
                    Bitmap resizedbitmap = Bitmap.createScaledBitmap(bm,
                            scr_height, scr_height + 30, true);

                    img1.setImageBitmap(resizedbitmap);

                    Bitmap resizedbitmap1 = Bitmap.createScaledBitmap(bm1,
                            scr_height, scr_height + 30, true);

                    img2.setImageBitmap(resizedbitmap1);
                }

            }



        } else if (action == MotionEvent.ACTION_MOVE && !multiTouch)
        {
            System.out.println("single2");
        }

        return super.onTouchEvent(event);

    }

    public class MySimpleOnScaleGestureListener extends
            SimpleOnScaleGestureListener {

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            // TODO Auto-generated method stub

            scaleFactor = detector.getScaleFactor();

            Log.v("scaleFactor >>>", scaleFactor + "");

            return true;
        }
    }

}

我的 main.xml 是

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:id="@+id/pinchlay" >


    <ImageView
        android:id="@+id/img_left"
        android:layout_width="320dp"
        android:layout_height="fill_parent"
        />

    <ImageView
        android:id="@+id/img_right"
        android:layout_width="320dp"
        android:layout_height="fill_parent"
        android:layout_alignParentRight="true"
        />

</RelativeLayout>

【问题讨论】:

    标签: android touch-event


    【解决方案1】:

    如果我理解正确,单点触摸不会导致 ACTION_POINTER_UP,而是 ACTION_UP。这就是为什么它没有检测到单根手指。请参阅此帖子以供参考: https://stackoverflow.com/a/4269592/1084813

    【讨论】:

    • 谢谢。我还单独尝试了 ACTION_UP 进行单点触控。但这只会触发,不会触发多点触控。
    • @Manikandan 使用 action_up 不会在需要时触发双击。你是如何克服这个问题的
    【解决方案2】:

    正如之前的海报所暗示的,单个触摸指针向上而不是动作向上有单独的事件。 motionEvents的顺序如下:

    1. ACTION_DOWN
    2. (ACTION_MOVE)
    3. ACTION_POINTER_DOWN
    4. (ACTION_MOVE)
    5. (ACTION_POINTER_ID_SHIFT)
    6. (向下重复尽可能多的手指)
    7. ACTION_POINTER_UP
    8. (重复直到只剩下一根手指)
    9. ACTION_UP

    Here's 是了解多点触控事件的好资源,但捕获它们的想法和最简单的方法是使用 switch 语句。我使用我找到的这个 TouchImageView here。它的作用是允许缩放和平移,如果您只是单击它,它会执行单击,因此您可以将该处理代码添加到 OnClickListener() 或仅将其插入到第 125 行。

    【讨论】:

    • 我按你说的用了。没用。我已经更新了我的代码。检查一下。
    • @Manikandan 我更新了上面的内容,为您指出了一个几乎完全符合您想要做的事情的开源实现。很好用,我自己用过
    • 我只需要用两根手指平移图像。我认为比例因子最适合我的要求。我还需要点击/触摸图片来做一些处理。
    • @Manikandan 如果是这样的话,只需在 switch 语句中进行更改,以便它执行您想要的操作。至于问题的单击/触摸图像部分,请参阅最后一段。如果执行的触摸是单击,则 imageView 将调用 onClick()
    • @JRaymond,我不想放大图像。我在屏幕的两侧有两个图像,如果我用两根手指捏住屏幕并将手指向外拖动,我需要减小图像的宽度并需要在图像之间的那个空间中显示另一个布局。当我拖动手指时,图像应该是正常大小。我还必须点击图片来做一些动作。
    【解决方案3】:

    我无法为单点触控重现 count==2。单点触摸对我来说是 1。 尝试在真实设备上调试您的代码,看看您实际拥有什么。

    将 event.getPointerId(i) 与 event.getPointerCount() 一起使用,看看这些实际的接触点是什么。

    【讨论】:

    • @Alex what is i in event.getPointerId(i).
    【解决方案4】:

    您必须为 MultiTouch 使用 PointerID。看到这个Complete Example

    private View.OnTouchListener OnTouchListener = new View.OnTouchListener() {
            public boolean onTouch(View view, MotionEvent event) { 
                int pointerIndex = ((event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT);
                int action = event.getAction() & MotionEvent.ACTION_MASK;
                int pointerId = event.getPointerId(pointerIndex);
                Log.i("", "Pointer ID = " + pointerId);
                switch (action) {
                case MotionEvent.ACTION_POINTER_UP: {
    
                    break;
                }
                }
                return true;
            }
        };
    

    【讨论】:

    • 我也想区分单点触控和多点触控。如果我做单点触摸,我需要执行一些操作。如果我做多点触控,我需要做不同的动作。
    【解决方案5】:

    您检查了ACTION_DOWN,但同时您还需要检查ACTION_POINTER_DOWN,这样更清楚。试试看

     @Override
        public boolean onTouchEvent(MotionEvent event) {    
             scaleGestureDetector.onTouchEvent(event);
    
             int action = event.getAction();
    
             if( (action == MotionEvent.ACTION_DOWN) && (action != MotionEvent.ACTION_POINTER_DOWN))
                 // Single touch
            else if ( action == MotionEvent.ACTION_POINTER_DOWN)
                //multi touch
    
            return true;
    }   
    

    编辑

    boolean multiTouch=false;
     @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
    
        int index= event.getActionIndex();
        int action = event.getAction();
    
        if( index ==1)
        {
            multiTouch=true;
            System.out.println("mutli");
        }
        else if (multiTouch==false)
            System.out.println("single");
        //else if (action== MotionEvent.ACTION_POINTER_1_UP)
        //  multiTouch=false;
        else if (action== MotionEvent.ACTION_MOVE && multiTouch)
            System.out.println("mutli");
        else if (action== MotionEvent.ACTION_MOVE && !multiTouch)
            System.out.println("single");
    
            return super.onTouchEvent(event);
    }
    

    已编辑:

     package com.pinch.detect;
    
    import java.io.BufferedInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    
    import android.app.Activity;
    import android.content.Context;
    import android.content.ContextWrapper;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Bundle;
    import android.util.FloatMath;
    import android.util.Log;
    import android.view.Display;
    import android.view.MotionEvent;
    import android.view.ScaleGestureDetector;
    import android.view.View;
    import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;
    
    public class PinchDetectorActivity extends Activity {
        TextView textGestureAction;
        ImageView img1, img2;
        static Bitmap bm, bm1;
    
    boolean multiTouch = false;
    Context context;
    float scaleFactor = 0.0f;
    float lastscale;
    int scr_width, scr_height;
    Display display;
    private ScaleGestureDetector scaleGestureDetector;
    
    /** Called when the activity is first created. */
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textGestureAction = (TextView) findViewById(R.id.GestureAction);
        img1 = (ImageView) findViewById(R.id.img_left);
        img2 = (ImageView) findViewById(R.id.img_right);
        display = getWindowManager().getDefaultDisplay();
    
        scr_width = display.getWidth();
        scr_height = display.getHeight();
        Log.v("width >>", Integer.toString(scr_width));
        Log.v("height >>", Integer.toString(scr_height));
    
        bm = BitmapFactory.decodeResource(this.getResources(),
                R.drawable.fiction1);
        img1.setImageBitmap(bm);
        bm1 = BitmapFactory.decodeResource(this.getResources(),
                R.drawable.fiction2);
        img2.setImageBitmap(bm1);
        img1.setScaleType(ImageView.ScaleType.FIT_START);
        img2.setScaleType(ImageView.ScaleType.FIT_END);
    
        scaleGestureDetector = new ScaleGestureDetector(this,
                new MySimpleOnScaleGestureListener());
    
    
    
        img1.setOnTouchListener(new OnTouchListener(){
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                system.out.println("Image 1 touched");
                return false;
            }
    
        });
    
    
    
    img2.setOnTouchListener(new OnTouchListener(){
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                system.out.println("Image 2 touched");
                return false;
            }
    
        });
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
    
        scaleGestureDetector.onTouchEvent(event);
        int index = event.getActionIndex();
        Log.v("Index value ",index+"");
        int action = event.getAction();
    
        if (index == 1) {
            multiTouch = true;
            System.out.println("mutli1");
        } else if (multiTouch == false) {
            System.out.println("single1");
            img1.onTouch(view, event);
    
        }
    
         else if (action == MotionEvent.ACTION_MOVE && multiTouch) {
            System.out.println("mutli2");
             img2.onTouch(view, event);
    
            if (scaleFactor > 1) {
    
                Bitmap resizedbitmap = Bitmap.createScaledBitmap(bm,
                        scr_width / 2, scr_height, true);
                img1.setImageBitmap(resizedbitmap);
                Bitmap resizedbitmap1 = Bitmap.createScaledBitmap(bm1,
                        scr_width / 2, scr_height, true);
                img2.setImageBitmap(resizedbitmap1);
                Log.v("width >>", Integer.toString(scr_width));
                Log.v("height >>", Integer.toString(scr_height));
    
            } else if(scaleFactor<1){
    
                Log.v("width >>", Integer.toString(scr_width));
                Log.v("height >>", Integer.toString(scr_height));
                if (scr_width >= 640) {
                    Bitmap resizedbitmap = Bitmap.createScaledBitmap(bm,
                            scr_height + 90, scr_height, true);
    
                    img1.setImageBitmap(resizedbitmap);
    
                    Bitmap resizedbitmap1 = Bitmap.createScaledBitmap(bm1,
                            scr_height + 90, scr_height, true);
    
                    img2.setImageBitmap(resizedbitmap1);
                } else {
                    Bitmap resizedbitmap = Bitmap.createScaledBitmap(bm,
                            scr_height, scr_height + 30, true);
    
                    img1.setImageBitmap(resizedbitmap);
    
                    Bitmap resizedbitmap1 = Bitmap.createScaledBitmap(bm1,
                            scr_height, scr_height + 30, true);
    
                    img2.setImageBitmap(resizedbitmap1);
                }
    
            }
    
    
    
        } else if (action == MotionEvent.ACTION_MOVE && !multiTouch)
        {
            System.out.println("single2");
        }
    
        return super.onTouchEvent(event);
    
    }
    
    public class MySimpleOnScaleGestureListener extends
            SimpleOnScaleGestureListener {
    
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            // TODO Auto-generated method stub
    
            scaleFactor = detector.getScaleFactor();
    
            Log.v("scaleFactor >>>", scaleFactor + "");
    
            return true;
        }
    }
    
    }
    

    最新:

    if (index == 1) {
            multiTouch = true;
            img2.onTouch(view, event);
        System.out.println("mutli1");
    } else if (multiTouch == false) {
        System.out.println("single1");
        img1.onTouch(view, event);
    
    }
    
     else if (action == MotionEvent.ACTION_MOVE && multiTouch) {
        System.out.println("mutli2");
    

    【讨论】:

    • 你可以试试 public class PinchDetectorActivity extends Activity implements OnTouchListener{ img1.setOnTouchListener(this);
    【解决方案6】:

    这里是检测点并用不同颜色绘制每个点的代码 get Competition example here

    public class custom_view extends View {
    
    
    
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    
    public int cu = 0;
    
    
    
    final int MAX_NUMBER_OF_POINT = 10;
    
    float[] x = new float[MAX_NUMBER_OF_POINT];
    
    float[] y = new float[MAX_NUMBER_OF_POINT];
    
    boolean[] touching = new boolean[MAX_NUMBER_OF_POINT];
    
    
    
    public custom_view(Context context, AttributeSet attrs, int defStyle) {
    
        super(context, attrs, defStyle);
    
        init();
    
    }
    
    public custom_view(Context context, AttributeSet attrs) {
    
        super(context, attrs);
    
        init();
    
    }
    
    
    
    public custom_view(Context context) {
    
        super(context);
    
        init();
    
    }
    
    void init() {
    
        paint.setStyle(Paint.Style.STROKE);
    
        paint.setStrokeWidth(40);
    
    }
    
    @Override
    
    protected void onDraw(Canvas canvas) {
    
        for (int i = 0; i < MAX_NUMBER_OF_POINT; i++) {
    
            if (touching[i]) {
    
                switch (i) {
    
                case 1:
    
                    paint.setColor(Color.BLUE);
    
                    break;
    
                case 2:
    
                    paint.setColor(Color.RED);
    
                    break;
    
                case 3:
    
                    paint.setColor(Color.CYAN);
    
                    break;
    
                case 4:
    
                    paint.setColor(Color.GREEN);
    
                    break;
    
                case 5:
    
                    paint.setColor(Color.YELLOW);
    
                    break;
    
                case 6:
    
                    paint.setColor(Color.MAGENTA);
    
                    break;
    
                case 7:
    
                    paint.setColor(Color.DKGRAY);
    
                    break;
    
                case 8:
    
                    paint.setColor(Color.LTGRAY);
    
                    break;
    
                case 9:
    
                    paint.setColor(Color.GREEN);
    
                    break;
    
                case 10:
    
                    paint.setColor(Color.BLACK);
    
    
    
                    break;
    
                    }
    
                canvas.drawCircle(x[i], y[i], 70f, paint);
    
            }
    
        }
    
    }
    
    @Override
    
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
    
                MeasureSpec.getSize(heightMeasureSpec));
    
    }
    
    @Override
    
    public boolean onTouchEvent(MotionEvent event) {
    
        int action = (event.getAction() & MotionEvent.ACTION_MASK);
    
        int pointCount = event.getPointerCount();
    
        for (int i = 0; i < pointCount; i++) {
    
            int id = event.getPointerId(i);
    
    
    
            if (id < MAX_NUMBER_OF_POINT) {
    
                x[id] = (int) event.getX(i);
    
                y[id] = (int) event.getY(i);
    
    
    
                if ((action == MotionEvent.ACTION_DOWN)
    
                        || (action == MotionEvent.ACTION_POINTER_DOWN)
    
                        || (action == MotionEvent.ACTION_MOVE)) {
    
                    touching[id] = true;
    
                } else {
    
                    touching[id] = false;
    
                    }
    
            }
    
        }
    
        invalidate();
    
        return true;
    
    }
    

    }

    【讨论】:

      【解决方案7】:

      您是否尝试过使用 OnDoubleTapListener

      发现这个tutorial 也很有帮助,它展示了如何检测单击和双击。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-23
        • 2015-05-18
        • 2011-05-02
        相关资源
        最近更新 更多