I have to let this slip for now as a purely academic issue but i would very much like to see a solution in near time.
Due to the way that Android handles multitouch you can (as i see it) only trap the event in a single view. I've tried an hack for this envolving a container layout that intercepts the events sees what View it belongs by seeing the coords and changing the action itself so that it seems to the component that it's a single touch event. I compose such events and then route it to the Views.
Does anyone have a better idea to do this?
If someone wants the code for what i described above just ask and i post it!
Have fun and good luck :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:splitMotionEvents
orandroid:windowEnableSplitTouch
. For applications for before Honeycomb, I would override theonInterceptTouchEvent
method of theViewGroup
. – Lampe