【问题标题】:Android multitouch! hack anyone?安卓多点触控!破解任何人?
【发布时间】:2011-08-21 18:59:15
【问题描述】:

作为一个纯粹的学术问题,我现在不得不放弃这个问题,但我非常希望在不久的将来看到解决方案。

由于 Android 处理多点触控的方式,您可以(如我所见)仅将事件捕获在单个视图中。我已经尝试了一个 hack,它包含一个拦截事件的容器布局,通过查看坐标并更改操作本身来查看它所属的视图,以便在组件看来它是一个单一的触摸事件。我编写此类事件,然后将其路由到视图。

有没有人有更好的主意来做这件事?

如果有人想要我上面描述的代码,请询问并发布!

玩得开心,祝你好运:D JQCorreia

public class Container extends LinearLayout
{      
        LinkedHashMap<Integer,View> pointers = new LinkedHashMap<Integer,View>();
        ArrayList<View> views  = new ArrayList<View>();

        public Container(Context context) {
                super(context);
                initialize(context);

        }

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

        private void initialize(Context context)
        {

        }
        @Override
        public void onLayout(boolean changed, int l, int t, int r, int b)
        {
                super.onLayout(changed, l, t, r, b);
                views = LayoutUtil.flattenLayout(this,false);
                for(View foo : views)
                {
                        Rect rect = new Rect();
                        foo.getGlobalVisibleRect(rect);
                }
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent event)
        {
                return true;
        }
        @Override
        public boolean onTouchEvent(MotionEvent event)
        {
                int action = event.getAction() & MotionEvent.ACTION_MASK;
                if(action==MotionEvent.ACTION_DOWN)
                {
                        for(View v: views)
                        {
                                Rect r = new Rect();
                                v.getGlobalVisibleRect(r);
                                if (event.getX() > r.left && event.getX() < r.right
                                                && event.getY() > r.top
                                                && event.getY() < r.bottom) {
                                        pointers.put(event.getPointerId(0),v);
                                        pointers.get(event.getPointerId(0)).onTouchEvent(event);
                                        break;
                                }
                        }
                }
                if(action==MotionEvent.ACTION_POINTER_DOWN)
                {
                        int pid = event.getAction() >> MotionEvent.ACTION_POINTER_ID_SHIFT;
                        int index = event.findPointerIndex(pid);

                        for(View v: views)
                        {

                                Rect r = new Rect();
                                v.getGlobalVisibleRect(r);
                                if (event.getX(index) > r.left
                                                && event.getX(index) < r.right
                                                && event.getY(index) > r.top
                                                && event.getY(index) < r.bottom) {


                                        pointers.put(pid,v);
                                        MotionEvent copy = MotionEvent.obtain(event);
                                        copy.setAction(MotionEvent.ACTION_DOWN);
                                        copy.setLocation(event.getX(index), event.getY(index));
                                        pointers.get(pid).onTouchEvent(copy);
                                }
                        }
                }
                if(action==MotionEvent.ACTION_POINTER_UP)
                {
                        int pid = event.getAction() >> MotionEvent.ACTION_POINTER_ID_SHIFT;
                        int index = event.findPointerIndex(pid);

                        if(pointers.get(pid)!=null) // If the touch was outside any view
                        {
                                MotionEvent copy = MotionEvent.obtain(event);
                                copy.setAction(MotionEvent.ACTION_UP);
                                pointers.get(pid).onTouchEvent(copy);
                                pointers.remove(pid);
                        }
                }

                if(action==MotionEvent.ACTION_MOVE)
                {
                        for(int i = 0; i<event.getPointerCount();i++)
                        {
                                int pid = event.getPointerId(i);
                                MotionEvent copy = MotionEvent.obtain(event);
                                copy.setLocation(event.getX(i), event.getY(i));

                                if(pointers.get(pid)==null) continue; // If the touch was outside any view
                                pointers.get(pid).onTouchEvent(copy);
                        }
                }

                if(action==MotionEvent.ACTION_UP)
                {
                        if(pointers.get(event.getPointerId(0))!=null)
                        {
                                pointers.get(event.getPointerId(0)).onTouchEvent(event);
                                pointers.remove(event.getPointerId(0));
                        }
                }
                return true;
        }

}

// This is the LayoutUtil.flattenLayout method
        public static ArrayList<View> flattenLayout(View view, boolean addViewGroups)
        {
                ArrayList<View> viewList = new ArrayList<View>();
                if(view instanceof ViewGroup)
                {
                        if(((ViewGroup)view).getChildCount()==0)
                                viewList.add(view);
                        else
                        {
                                if(addViewGroups)
                                {
                                        viewList.add(view);
                                }
                                ViewGroup viewgroup = (ViewGroup) view;
                                for(int i = 0; i < viewgroup.getChildCount();i++)
                                {
                                        viewList.addAll(flattenLayout(viewgroup.getChildAt(i),false));
                                }
                        }      
                }
                else if(view instanceof View)
                {
                        viewList.add(view);
                }
                return viewList;
        }

【问题讨论】:

  • 这在 Android 3.0 (developer.android.com/sdk/android-3.0.html) 中有所改变,您可以使用android:splitMotionEventsandroid:windowEnableSplitTouch。对于 Honeycomb 之前的应用程序,我会覆盖 ViewGrouponInterceptTouchEvent 方法。
  • 谢谢我不知道...
  • 但无论如何,直到我们在大多数设备中使用 3.0 之前,这个线程可能是解决这个问题的“坦克”。至少这是我的想法:D
  • 没有评论权限的用户发表评论 (Ravs):JQCorreia,您能指出我们的代码吗?
  • Anne 或 Ravs(我不明白谁在问 =))它是:pastebin.com/hiE1aTCw

标签: android multi-touch


【解决方案1】:

这里最好的解决办法是放

android:splitMotionEvents = false 

在 LinearLayout 或您的视图(按钮、TextView 等)所在的任何布局中。

-欢呼快乐的编码

【讨论】:

    【解决方案2】:

    您还需要覆盖 onInterceptTouchEvent 以捕获运动事件。当您从 onInterceptTouchEvent 返回 true 时,所有后续事件(无论是否在您的视图边界内)都会在对 onTouchEvent 的调用中被捕获,直到(包括)最后一个指针上升的点。

    传统上,您在 onInterceptTouchEvent 中放置了足够的逻辑来确定指针已经下降,并且在返回 true 之前它已经移动超过某个阈值,但这取决于您是否要支持水平和/或垂直方向的拖动家长意见。如果 ACTION_POINTER_DOWN 事件足以触发捕获,则可以立即返回 true。

    【讨论】:

    • 是的。但请注意,只有在子视图将处理真正的 onTouchEvent(例如可点击)时才会调用 onInterceptTouchEvent。否则,您只会得到 onTouchEvent,因为没有人可以从中“拦截”事件。
    【解决方案3】:
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(ev.getPointerCount() > 1) return false;
        return super.dispatchTouchEvent(ev);
    }
    

    在活动或视图中插入此内容

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多