我现在不得不放弃这个纯粹的学术问题,但我非常希望能在近期看到解决方案。
由于Android处理多点触控的方式,你可以(我认为)只在一个视图中捕获事件。我已经尝试了一个hack来解决这个容器布局,拦截事件通过查看coords并更改动作本身来查看它所属的View,这样组件看起来就是单个触摸事件。我撰写此类事件,然后将其路由到视图。
有人有更好的想法吗?
如果有人想要我上面描述的代码只是问我发布它!
玩得开心,祝你好运: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;
}
答案 0 :(得分:9)
这里最好的解决方案是
android:splitMotionEvents = false
在LinearLayout内部或任何布局视图(Button,TextView等)。
- 快乐编码
答案 1 :(得分:2)
您还需要覆盖onInterceptTouchEvent以捕获运动事件。当您从onInterceptTouchEvent返回true时,所有后续事件(无论是否在视图边界内)都会在调用onTouchEvent时捕获,直到(并包括)最后一个指针上升的点。
传统上,你在onInterceptTouchEvent中放置了足够的逻辑来确定指针已经关闭,并且它在返回true之前已经移动超过某个阈值,但这取决于你是否想要支持水平和/或垂直方向的拖动家长意见。如果ACTION_POINTER_DOWN事件足以触发捕获,则可以立即返回true。
答案 2 :(得分:0)
RefinementFilters
在活动或视图上插入