cialis 100mg preis natürliches viagra apotheke kamagra sicher online kaufen cialis preis thailand kann man kamagra in jeder apotheke kaufen

Multitouch for all Views

Here is the new Version of my implementation of the MultiTouchActivity.

screenshot2

 

Features:

  • forwards all MotionEvents to the underlying View
  • Included Move Events
  • Sends MouseUp to View if the pointer is out of the View
  • sends MoveEvents  to a View if the Pointer is outside of the View (but registered to view with MouseDown) if you add the View to the moveOutsideEnabledViews  with addMoveOutsideEnabledViews(View);. (see the TestButton)

Further informations:

Download Example App:


logo-app
App Name
Developer
Free   
pulsante-google-play-store
pulsante-appbrain
qrcode-app

Get full Project Source here:

Have a quick look at the Code here:

package de.passsy.multitouch;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;

public class MultiTouchActivity extends Activity implements OnTouchListener {

	private View parent;

	private final ArrayList[] recentTouchedViewsIndex = new ArrayList[10];

	private final ArrayList[] downTouchedViewsIndex = new ArrayList[10];

	private final ArrayList<view> moveOutsideEnabledViews = new ArrayList<view>();

	private int mTouchSlop = 24;

	public void addMoveOutsideEnabledViews(final View view) {
		moveOutsideEnabledViews.add(view);
	}

	private void dealEvent(final int actionPointerIndex,
			final MotionEvent event, final View eventView,
			final int actionResolved) {
		int rawX, rawY;
		final int location[] = { 0, 0 };
		eventView.getLocationOnScreen(location);
		// Log.v(&quot;tag&quot;, location + &quot;&quot;);
		rawX = (int) event.getX(actionPointerIndex) + location[0];
		rawY = (int) event.getY(actionPointerIndex) + location[1];

		final int actionPointerID = event.getPointerId(actionPointerIndex);
		ArrayList<view> hoverViews = getTouchedViews(rawX, rawY);

		if (actionResolved == MotionEvent.ACTION_DOWN) {
			downTouchedViewsIndex[actionPointerID] = (ArrayList<view>) hoverViews
					.clone();
		}
		// deletes all views which where not clicked on ActionDown
		if (downTouchedViewsIndex[actionPointerID] != null) {
			final ArrayList<view> tempViews = (ArrayList<view>) hoverViews
					.clone();
			tempViews.removeAll(downTouchedViewsIndex[actionPointerID]);
			hoverViews.removeAll(tempViews);
		}

		if (recentTouchedViewsIndex[actionPointerID] != null) {
			final ArrayList<view> recentTouchedViews = recentTouchedViewsIndex[actionPointerID];

			final ArrayList<view> shouldTouchViews = (ArrayList<view>) hoverViews
					.clone();
			if (!shouldTouchViews.containsAll(recentTouchedViews)) {
				shouldTouchViews.removeAll(recentTouchedViews);
				shouldTouchViews.addAll(recentTouchedViews);

				final ArrayList<view> outsideTouchedViews = (ArrayList<view>) shouldTouchViews
						.clone();
				outsideTouchedViews.removeAll(hoverViews);
			}

			recentTouchedViewsIndex[actionPointerID] = hoverViews;
			hoverViews = shouldTouchViews;
		} else {
			recentTouchedViewsIndex[actionPointerID] = hoverViews;
		}

		if (actionResolved == MotionEvent.ACTION_UP) {
			recentTouchedViewsIndex[actionPointerID] = null;
			downTouchedViewsIndex[actionPointerID] = null;
		}

		dumpEvent(event);
		for (final View view : hoverViews) {
			int x, y;
			view.getLocationOnScreen(location);
			x = rawX - location[0];
			y = rawY - location[1];

			// View does not recognize that the Pointer is
			// outside if the Pointer is not far away (&gt;mTouchSlop)
			if (recentTouchedViewsIndex[actionPointerID] != null) {
				if (pointInView(x, y, mTouchSlop, view.getWidth(),
						view.getHeight())) {
					// Log.v(&quot;tag&quot;, &quot;added because &lt; mTouchSlop&quot;);

					if (!recentTouchedViewsIndex[actionPointerID]
							.contains(view)) {
						recentTouchedViewsIndex[actionPointerID].add(view);
					}
				} else if (moveOutsideEnabledViews.contains(view)) {
					Log.v(&quot;tag&quot;, &quot;outside but gets event&quot;);
					recentTouchedViewsIndex[actionPointerID].add(view);
				}
			}
			final MotionEvent me = MotionEvent.obtain(event.getDownTime(),
					event.getEventTime(), actionResolved, x, y,
					event.getPressure(actionPointerIndex),
					event.getPressure(actionPointerIndex),
					event.getMetaState(), event.getXPrecision(),
					event.getYPrecision(), event.getDeviceId(),
					event.getEdgeFlags());
			me.setLocation(x, y);

			if (!me.equals(event)) {
				// deals the Event
				view.onTouchEvent(me);
			}

			// debug
			if (actionResolved == MotionEvent.ACTION_MOVE) {
				Log.v(&quot;tag&quot;,
						&quot;#&quot; + actionPointerIndex + &quot; Rawx:&quot; + rawX + &quot; rawy:&quot;
								+ rawY + &quot; x:&quot; + x + &quot; y:&quot; + y + &quot; &quot;
								+ view.toString());
			}
		}

	}

	private void dumpEvent(final MotionEvent event) {
		final String names[] = { &quot;DOWN&quot;, &quot;UP&quot;, &quot;MOVE&quot;, &quot;CANCEL&quot;, &quot;OUTSIDE&quot;,
				&quot;POINTER_DOWN&quot;, &quot;POINTER_UP&quot;, &quot;7?&quot;, &quot;8?&quot;, &quot;9?&quot; };
		final StringBuilder sb = new StringBuilder();
		final int action = event.getAction();
		final int actionCode = action &amp; MotionEvent.ACTION_MASK;
		sb.append(&quot;event ACTION_&quot;).append(names[actionCode]);
		if (actionCode == MotionEvent.ACTION_POINTER_DOWN
				|| actionCode == MotionEvent.ACTION_POINTER_UP) {
			sb.append(&quot;(pid &quot;).append(
					action &gt;&gt; MotionEvent.ACTION_POINTER_ID_SHIFT);
			sb.append(&quot;)&quot;);
		}
		sb.append(&quot;[&quot;);
		for (int i = 0; i &lt; event.getPointerCount(); i++) {
			sb.append(&quot;#&quot;).append(i);
			sb.append(&quot;(pid &quot;).append(event.getPointerId(i));
			sb.append(&quot;)=&quot;).append((int) event.getX(i));
			sb.append(&quot;,&quot;).append((int) event.getY(i));
			if (i + 1 &lt; event.getPointerCount()) {
				sb.append(&quot;;&quot;);
			}
		}
		sb.append(&quot;]&quot;);
		Log.d(&quot;tag&quot;, sb.toString());
	}

	private ArrayList<view> getChildViews(final View view) {
		final ArrayList<view> views = new ArrayList<view>();
		if (view instanceof ViewGroup) {
			final ViewGroup v = ((ViewGroup) view);
			if (v.getChildCount() &gt; 0) {
				for (int i = 0; i &lt; v.getChildCount(); i++) {
					views.add(v.getChildAt(i));
				}

			}
		}
		return views;
	}

	private ArrayList<view> getTouchedViews(final int x, final int y) {

		final ArrayList<view> touchedViews = new ArrayList<view>();
		final ArrayList<view> possibleViews = new ArrayList<view>();

		if (parent instanceof ViewGroup) {
			possibleViews.add(parent);
			for (int i = 0; i &lt; possibleViews.size(); i++) {
				final View view = possibleViews.get(i);

				final int location[] = { 0, 0 };
				view.getLocationOnScreen(location);

				if (((view.getHeight() + location[1] &gt;= y)
						&amp; (view.getWidth() + location[0] &gt;= x)
						&amp; (view.getLeft() &lt;= x) &amp; (view.getTop() &lt;= y))
						|| view instanceof FrameLayout) {
					touchedViews.add(view);
					possibleViews.addAll(getChildViews(view));
				}

			}
		}

		return touchedViews;

	}

	@Override
	public void onCreate(final Bundle instance) {
		super.onCreate(instance);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
		getWindow().clearFlags(
				WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
		parent = findViewById(android.R.id.content).getRootView();
		parent.setOnTouchListener(this);
		mTouchSlop = ViewConfiguration.get(getApplicationContext())
				.getScaledTouchSlop();
	}

	@Override
	public boolean onTouch(final View v, final MotionEvent event) {

		// index of the pointer which starts this Event
		final int actionPointerIndex = event.getActionIndex();

		// resolve the action as a basic type (up, down or move)
		int actionResolved = event.getAction() &amp; MotionEvent.ACTION_MASK;
		if (actionResolved &lt; 7 &amp;&amp; actionResolved &gt; 4) {
			actionResolved = actionResolved - 5;
		}

		if (actionResolved == MotionEvent.ACTION_MOVE) {
			for (int ptrIndex = 0; ptrIndex &lt; event.getPointerCount(); ptrIndex++) {
				// only one event for all move events.
				dealEvent(ptrIndex, event, v, actionResolved);
				Log.v(&quot;tag&quot;, &quot;move&quot; + ptrIndex);
			}

		} else {
			dealEvent(actionPointerIndex, event, v, actionResolved);
		}

		return true;
	}

	private boolean pointInView(final float localX, final float localY,
			final float slop, final float width, final float height) {
		return localX &gt;= -slop &amp;&amp; localY &gt;= -slop &amp;&amp; localX &lt; ((width) + slop)
				&amp;&amp; localY &lt; ((height) + slop);
	}
}
package de.passsy.multitouch;

import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.SeekBar;

public class MultitouchtestActivity extends MultiTouchActivity {
	/** Called when the activity is first created. */

	private Button btn1;
	private Button btn2;
	private Button btn3;
	private TestButton btn4;
	private SeekBar seekbar;

	@Override
	public void onCreate(final Bundle savedInstanceState) {
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
		getWindow().clearFlags(
				WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		btn1 = (Button) findViewById(R.id.button1);
		btn1.setText("My Multitouch is not enabled");
		btn2 = (Button) findViewById(R.id.button2);
		btn2.setOnTouchListener(this);
		btn2.setText("My Multitouch is enabled");
		btn3 = (Button) findViewById(R.id.button3);
		btn3.setOnTouchListener(this);
		btn3.setText("My Multitouch is enabled");
		btn4 = (TestButton) findViewById(R.id.button4);
		btn4.setOnTouchListener(this);
		addMoveOutsideEnabledViews(btn4);
		seekbar = (SeekBar) findViewById(R.id.seekbar);
		seekbar.setOnTouchListener(this);
		addMoveOutsideEnabledViews(seekbar);
	}
}
package de.passsy.multitouch;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Button;

public class TestButton extends Button {

	public TestButton(final Context context, final AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean onTouchEvent(final MotionEvent event) {
		Log.v("tag", "I get touched");
		setText("I recive a MotionEvent");
		if (event.getAction() == MotionEvent.ACTION_UP) {
			setText("I can recive Move events outside of my View");
		}
		return super.onTouchEvent(event);
	}
}
, , , , , , , , , , , , , , , , , , ,

29 Comments

  • […] Activity with multitouch for Buttons Januar 11 2012 by passsy in Android, Software |1 Comment new Version avaiable here: http://www.passsy.de/multitouch-for-all-views/ […]

  • Chen sagt:

    Briiliant work! Really useful!

  • Nash sagt:

    Thank you so much…very usefull!! It would be awesome if you include seekbar listener example

  • Giuseppe sagt:

    Good job!
    I have a question, how I can use multitouch to know when the user touches the buttons and not know when the user clicks (touch-and-release)?

  • Giuseppe sagt:

    Good job!
    I have a question, how I can use multitouch to know when the user touches the buttons and not when the user clicks (touch-and-release the buttons)?
    for example: i whant to extend this to multitouch:

    btnStartGame.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
    if(event.getAction()==MotionEvent.ACTION_DOWN)
    {
    callSomeFunction();
    }
    return true;
    }
    });

    thanks 😉

  • passsy sagt:

    Look in the example in TestButton.java

    just pass your code in the onTouchEvent methode

    @Override
    public boolean onTouchEvent(final MotionEvent event) {
    if(event.getAction()==MotionEvent.ACTION_DOWN) {
    callSomeFunction();
    }
    return super.onTouchEvent(event);
    }

    You always have to extend the standard Controls and override the onTouchEvent Methode.

  • Giuseppe sagt:

    thanks for the reply, now works 🙂

  • Giuseppe sagt:

    One last question:
    how I can handle the event in the MultitouchtestActivity class without calling a static method from TestButton?
    thanks 🙂

  • Hassy sagt:

    Hi
    good job!this is really useful.
    I have a question.
    I want to create two buttons and get the MotionEvent.ACTION_MOVE at
    same time and I want to get which button was clicked and action_moved fired.
    how can I get button Id ?

    thanks a lot.

  • Senén sagt:

    Hello, and thanks for your job.
    I have exacly the same question as Hassy.
    Could you help us?
    Thanks again

  • passsy sagt:

    Sorry I don’t get it. Can you give me a real example?

    You can create a new listener and register a event on it. Does it help?

  • Senén sagt:

    I’m kind off starting with Android so sorry if I don’t explain myself properly or I dont get what you are explaining.
    What I want to do is to press two buttons at the same time, when „down“ do something, and when „up“ do something else. Different actions for each button.
    If I create two TestButton they do the same thing. And if I create a „btn5.setOnTouchListener(new OnTouchListener() {})“ on MultitouchtestActivity I lose the moultitouch property.
    Is it clear now?
    Thx 🙂

  • Hassy sagt:

    Hi again

    I solved the problem.I was able to create two buttons and get the MotionEvent.ACTION_MOVE at same time!

    I created a method in TestButton(custom button) class and it returns boolean.
    public boolean getFlg() {
    return flg;
    }

    if (event.getAction() == MotionEvent.ACTION_MOVE) {
    flg = true;
    getFlg();
    }

    //get action moved
    if (Button1.getFlg() == true && Button2.getFlg() == true) {
    Log.v(„Both“, „Moved!“);
    }

    I think this could help Senén too.

    thank you.

  • Giuseppe sagt:

    Hello, sometimes when I press the buttons very quickly I have a bug like this:
    http://pastebin.com/D5vHJ9vF
    how can I fix this?
    thanks

  • passsy sagt:

    are you using the latest version? I can’t reproduce this error. Ideed line 50 is a comment line. Did you changed something in code?

  • Giuseppe sagt:

    Yes, i use the latest version.
    I did not change anything, I just added @SuppressWarning.
    my line 50 is original line 47:
    downTouchedViewsIndex[actionPointerID] = (ArrayList) hoverViews
    .clone();

    Thanks for reply 🙂

  • newbie sagt:

    i get the following error when building the project with „ant debug“

    can you help me how to fix it?

    [javac] C:\android\tools\multitouchtest\src\de\passsy\multitouch\MultiTouchActivity.java:217: cannot find symbol
    [javac] symbol : method getActionIndex()
    [javac] location: class android.view.MotionEvent
    [javac] final int actionPointerIndex = event.getActionIndex();
    [javac] ^
    [javac] 1 error
    [javac] 7 warnings

    BUILD FAILED

  • Miguel sagt:

    Hi,

    is there a way I could get the ’sliding‘ to work? So that if I touch and move from button to button the button selection follows the movement.

    Thanks

  • passsy sagt:

    It’s kind of tricky. I’m not sure, but i think the buttons receive the move event. But they need an onPointerDown Event to change their state.

    but i think your are on your own 😉 but it shouldn’t be too hard to implement this

  • phani sagt:

    How to use this code when tab Activity is parent to our Activity.

  • Alex sagt:

    Hey!

    At first, i wanna say thanks for this project, it’s awesome!

    Might you please show, how to set different actions on e.g. button 2 and 3? That would be so great!

    nice blog btw

  • rob sagt:

    Hi !

    nice code, works like magic 🙂 except one case 🙁

    i try to use 2 seekbars, one of them rotated for 90° or 270°

    so when i touch the vertical first only this one works

    when i touch the horizontal seekbar first, the vertical works too
    but has behavior like a horizontal

    is there trick to fix this?

    greets rob

  • passsy sagt:

    I think you just overwrote the onDraw method to rotate the Seekbar by 90°. you have to override the onTouch method too.

  • koko sagt:

    hii,i newbie on android developing,i want to make a simple piano aplication,but i have a trouble to make my aplication support multitouch,i still be confuse to make it,,

    i have 3 buttons,when i press buttonA,play soundA,and when i press buttonB,play soundB,and then when i press buttonC,play SoundC.now i have trouble when i want to press two buttons on same time,ex buttonA & buttonC,the sound is not playing,how can resolve it ?

  • loco sagt:

    how to i know which button i press on class testbutton,example..

    public boolean onTouchEvent(final MotionEvent event) {
    Log.v(„tag“, „I get touched“);
    setText(„I recive a MotionEvent“);
    if (event.getAction() == MotionEvent.ACTION_UP) {
    if ( i press button1 ) do methodA
    if ( i press button2 ) do methodB
    }
    return super.onTouchEvent(event);
    }
    how we know user click button1 or button2, or both.. thanks 🙂

  • Umer Farooq sagt:

    Great Job..!!

Schreibe einen Kommentar

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>