【问题标题】:How to get total count of pointers when pointers are on multiple views?当指针位于多个视图上时,如何获取指针的总数?
【发布时间】:2016-06-15 07:58:41
【问题描述】:

当多个指针在不同的视图上时,如何获取屏幕上的指针总数?我在屏幕上有多个视图,如果指针不在视图的相关区域上,则视图将在 ON_DOWNonTouchEvent 情况下返回 false

当第一根手指在一个视图上并且第二根手指触摸另一个视图时,两个视图都将为getPointerCount 方法返回“1”。无论哪个视图处理指针的触摸,有什么方法可以获取整个屏幕上的总指针计数?

编辑: Views 不在同一个父 ViewGroup 中,这就是为什么 onInterceptTouch 不会返回总指针数。我可以将onInterceptTouch 放入非常根目录ViewGroup,但是我希望Android 能够提供指针总数,而不需要像这样的一些肮脏的解决方法。

【问题讨论】:

  • 所有视图都作为根视图驻留在 ViewGroup 中。 ViewGroup 类有方法:onInterceptTouch()。只要您从中返回 false,事件就会通过它传递,然后传递给子视图。所以,理论上,Views的父ViewGroup可以监控所有的指针。不过,您需要进行测试才能确定。

标签: android motionevent android-touch-event


【解决方案1】:

没有直接的方法可以使用Activity 上调用的方法,而是使用@S.D.指出,您可以使用ViewGrouponInterceptTouchEvent 来做到这一点:

MyLinearLayout.java

public class MyLinearLayout extends LinearLayout {
    public MyLinearLayout(Context context) {
        super(context);
    }

    public MyLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(21)
    public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onInterceptTouchEvent(final MotionEvent ev) {
        Log.e("TOUCHES", "num: " + ev.getPointerCount());

        return super.onInterceptTouchEvent(ev);
    }
}

mylayout.xml

<mypackage.MyLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/t1"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.5"
        android:clickable="true"
        android:gravity="center"
        android:text="0"/>

    <TextView
        android:id="@+id/t2"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.5"
        android:clickable="true"
        android:gravity="center"
        android:text="0"/>

</mypackage.MyLinearLayout>

MyActivity.java

public class MapsActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mylayout);

        final TextView t1 = (TextView) findViewById(R.id.t1);
        final TextView t2 = (TextView) findViewById(R.id.t2);

        t1.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(final View view, final MotionEvent motionEvent) {
                t1.setText(""+motionEvent.getPointerCount());
                return true;
            }
        });

        t2.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(final View view, final MotionEvent motionEvent) {
                t2.setText(""+motionEvent.getPointerCount());
                return true;
            }
        });
    }
}

本例会将TextViews的t1和t2的文本设置为每个MotionEvent接收到的getPointerCount(),并将记录MotionEventgetPointerCount()的总值收到MyLinearLayout

【讨论】:

    【解决方案2】:

    您需要一个自定义 ViewGroup 来拦截所有传递的触摸事件。

    您需要了解它在 Android 中的工作原理:

    • ViewGroup.onInterceptTouchEvent(MotionEvent) 允许 ViewGroup 在触摸事件到达孩子之前拦截它们。如果您在此处返回true,您将在onTouchEvent() 中收到后续触摸事件,并且在当前事件结束之前,孩子将不会再收到任何触摸事件(指针已移除)
    • 子视图可以使用ViewGroup.requestDisallowInterceptTouchEvent(boolean) 请求父视图禁止拦截:它们通常在识别正在进行的触摸事件并且不希望父视图中断它时这样做。如果 ViewGroup 收到此请求,它必须将其传递给父级并兑现它(= 从此不再拦截事件)
    • 在收到requestDisallowInterceptTouchEvent(true) 后,内部ViewGroup 不会调用onInterceptTouchEvent

    如果您需要监听每个触摸事件,即使孩子不允许拦截,您也需要欺骗ViewGroup 认为它没有被禁止,但您仍然需要遵守禁止(避免拦截触摸事件)。

    这是我为我的一个项目编写的课程,正是这样做的:

    public class InterceptTouchFrameLayout extends FrameLayout {
        private boolean mDisallowIntercept;
    
        public interface OnInterceptTouchEventListener {
            /**
             * If disallowIntercept is true the touch event can't be stealed and the return value is ignored.
             * @see android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
             */
            boolean onInterceptTouchEvent(InterceptTouchFrameLayout view, MotionEvent ev, boolean disallowIntercept);
    
            /**
             * @see android.view.View#onTouchEvent(android.view.MotionEvent)
             */
            public boolean onTouchEvent(InterceptTouchFrameLayout view, MotionEvent event);
        }
    
        private static final class DummyInterceptTouchEventListener implements OnInterceptTouchEventListener {
            @Override
            public boolean onInterceptTouchEvent(InterceptTouchFrameLayout view, MotionEvent ev, boolean disallowIntercept) {
                return false;
            }
            @Override
            public boolean onTouchEvent(InterceptTouchFrameLayout view, MotionEvent event) {
                return false;
            }
        }
    
        private static final OnInterceptTouchEventListener DUMMY_LISTENER = new DummyInterceptTouchEventListener();
    
        private OnInterceptTouchEventListener mInterceptTouchEventListener = DUMMY_LISTENER;
    
        public InterceptTouchFrameLayout(Context context) {
            super(context);
        }
    
        public InterceptTouchFrameLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public InterceptTouchFrameLayout(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
            getParent().requestDisallowInterceptTouchEvent(disallowIntercept);
            mDisallowIntercept = disallowIntercept;
        }
    
        public void setOnInterceptTouchEventListener(OnInterceptTouchEventListener interceptTouchEventListener) {
            mInterceptTouchEventListener = interceptTouchEventListener != null ? interceptTouchEventListener : DUMMY_LISTENER;
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            boolean stealTouchEvent = mInterceptTouchEventListener.onInterceptTouchEvent(this, ev, mDisallowIntercept);
            return stealTouchEvent && !mDisallowIntercept || super.onInterceptTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            boolean handled = mInterceptTouchEventListener.onTouchEvent(this, event);
            return handled || super.onTouchEvent(event);
        }
    }
    

    您只需将侦听器设置为:view.setOnInterceptTouchEventListener()

    在该侦听器中,您可以向下计数指针(在onIntercetTouchEvent() 方法中)。 只需将该布局作为布局的根目录(全屏)。

    如果您尝试在不使用禁止技巧的情况下执行相同操作,您最终可能会得到不正确的信息,因为您没有被授予接收所有触摸事件的权限。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-07
      • 1970-01-01
      • 2017-03-27
      • 2015-05-19
      • 2012-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多