如何在onTouchEvent()中检测单点触控和多点触控

13

我使用了以下代码来检测单指触摸和双指触摸。当count==2时,代码可以检测到双指触摸。

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

@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中使用了这段代码。我需要检测单点触摸和多点触摸。

在我的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>
7个回答

17

谢谢。我也尝试过单独使用ACTION_UP来触发单点触控,但那只会触发单点触控,而不是多点触控。 - Manikandan
@Manikandan使用action_up时无法触发所需的双击操作。您是如何解决这个问题的? - elixir bash

5
正如前面的帖子所建议的那样,单个触摸指针向上与动作向上有不同的事件。运动事件的顺序如下:
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
这里是一个很好的了解多点触控事件的资源(链接),但是捕获它们所有的想法和最简单的方法是使用switch语句。我使用了我在(链接)找到的TouchImageView。它允许缩放、平移,如果你只是点击它,它会执行点击,所以你可以将处理代码添加到OnClickListener()中,或者只需在第125行插入即可。

我按照你说的使用了,但没有用。我已经更新了我的代码,请检查一下。 - Manikandan
@Manikandan 我更新了上面的内容,指向一个开源实现,几乎完全符合你想要做的事情。它运行良好,我自己也使用过。 - JRaymond
我需要仅使用两根手指来平移图像。我认为缩放因子是满足我的需求的最佳选择。我还需要点击或触摸图像以执行一些处理。 - Manikandan
@Manikandan 如果是这种情况,只需在switch语句中改变事物的顺序,以便它按照您想要的方式运行。至于您问题中关于单击/触摸图像的部分,请参见最后一段。如果执行的触摸是单击,则会调用imageView的onClick()函数。 - JRaymond
@ JRaymond,我不想放大图片。屏幕的两侧有两张图片,如果我用两个手指捏住屏幕并向外拖动,我需要减小图片的宽度,并在图像之间的空间中显示另一个布局。当我将手指向内拖动时,图像应该是正常大小。此外,我必须点击图像执行一些操作。 - Manikandan

1

你已经检查了 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");

你可以尝试使用公共类PinchDetectorActivity扩展Activity并实现OnTouchListener接口: img1.setOnTouchListener(this); - Mohammed Azharuddin Shaikh

1

你必须使用PointerID来处理多点触控。请查看这个完整示例

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;
        }
    };

1
我还想区分单点触控和多点触控。如果我进行单点触控,我需要执行某些操作。如果我进行多点触控,我需要执行不同的操作。 - Manikandan

1

我无法复现单点触摸的count==2。对于单点触摸,我的计数是1。 尝试在真实设备上调试你的代码,看看你实际得到了什么。

使用event.getPointerId(i)以及event.getPointerCount(),查看这些实际触摸点是什么。


@ Alex,event.getPointerId(i) 中的 i 是什么? - Manikandan

1
这是检测点并以不同颜色绘制每个点的代码,获取完整的 示例
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;

}

}


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接