Wie gehe ich mit touch-Ereignisse richtig in android?
Rahmen des Projekts
Wenn ein Benutzer berührt den Android-Bildschirm mit zwei Fingern, und ziehen Sie ein "Rahmen" bei jeder Berührung Position mit einem "cursor" für jeden frame. Jeder frame eine benutzerdefinierte Schieberegler, bewegt sich der cursor nach oben und unten. Den ganzen Weg bis zu 100%, Mitte 0% und alle dem Weg nach unten werden -100%. Diese Steuern werden kleine Motoren, ähnlich dem tank drehen, jeder touch-Steuerung, die einen separaten motor (senden von Signalen über bluetooth). Nach zwei touch-und alles gezeichnet ist, will ich in der Lage, heben Sie entweder die finger, SONDERN halten Sie den cursor auf was auch immer Ort, es war die Letzte an, während die anderen finger frei zu bewegen und seinen cursor. Wenn der Letzte finger ist abgehoben, alles "versteckt" und setzt die auf 0%.
Funktionalität Wollte
- Auf zwei-finger-touch, ziehen, trennen .pngs unter der touch-Position
- Nach den frames und der Cursor gezeichnet werden, behalten Sie den überblick, wo Sie relativ zu dem Rahmen zu bestimmen, der Anteil.
- Wenn ein finger abgehoben, zu halten, dass die Finger der cursor an der letzten bekannten Position, aber die anderen finger bewegen kann, es ist cursor. Auch wenn die finger wieder down es in der Lage sein sollten, bewegen Sie den cursor wieder.
- Wenn beide Finger sind abgehoben von dem Bildschirm, blendet alles aus und reset-Prozentsätze 0%
Funktionalität Erhalten
- Ich kann zeichnen der Rahmen und Cursor auf multitouch -
- Positionen und Prozentsätze funktionieren
- Cursor richtig bewegen
, Was nicht funktioniert
- Ich bin nicht sicher, ob ich sollte eine custom-Klasse, die Griffe sowohl auf touch-als Ereignis oder wenn ich 2 Instanzen des benutzerdefinierten Klasse jeden Umgang mit Ihren eigenen touch-Ereignisse (ich habe beide ausprobiert, der einzige Weg, bekomme ich keine "echte" Funktion ist mit 1 benutzerdefinierten Klasse zur Verarbeitung von touch-events, die andere Weise nicht funktioniert, wie gedacht)
- Wenn ich nur 1 custom-Klasse, Es funktioniert Super, aber ich habe es "verstecken" sich alles, wenn die beiden die Finger nicht auf dem Bildschirm, und manchmal android registriert, dass ich den finger gehoben aus dem Bildschirm, und das verursacht mir eine Menge Fragen, wenn die frames zu verstecken, dann wieder auftauchen in einem anderen Ort
- Wenn ich 2 benutzerdefinierte Klassen, die ich berühren jede benutzerdefinierte Klasse hat Ihren eigenen touch-event, und ich würde nicht sorgen zu machen über multitouch, wenn ich teilen Sie die Klassen gleichmäßig auf dem Bildschirm. War dies nicht der Fall, müssen noch viel mit multitouch
Kann mir jemand erklären, wie android behandelt Ihre touch-Ereignisse. von dem, was ich getan habe, es scheint, wenn ich lay down finger 1, finger 2, der erste finger registrieren Sie einen "ACTION_DOWN" und mit dem zweiten register "ACTION_POINTER_2_DOWN", ABER wenn ich das Leben von meinem ersten finger, meine zweite finger ist "degradiert" und jetzt alle die Ereignisse meines zweiten finger Register jedoch nicht im Zusammenhang mit "ACTION_POINTER_2", sondern "ACTION_DOWN, ACTION_UP, etc". Ist das richtig?
TouchUI.java
package com.robota.android;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ImageView;
public class TouchUI extends ImageView {
public static final String LEFT_TOUCHUI = "com.robota.android:id/leftTouchUI";
public static final String RIGHT_TOUCHUI = "com.robota.android:id/rightTouchUI";
private String whoAmI = new String();
private MyPoints framePts = new MyPoints();
private MyPoints cursorPts = new MyPoints();
private Bitmap frame;
private Bitmap cursor;
private int frameWidth;
private int frameHeight;
private int cursorHeight;
private boolean pointerDown = false;
private int dy;
public TouchUI(final Context context, final AttributeSet as){
super(context, as);
Log.d("TouchUI", getResources().getResourceName(this.getId()));
whoAmI = new String(getResources().getResourceName(this.getId()));
if(whoAmI.equals(LEFT_TOUCHUI)){
frame = BitmapFactory.decodeResource(getResources(), R.drawable.tank_left);
}else if(whoAmI.equals(RIGHT_TOUCHUI)){
frame = BitmapFactory.decodeResource(getResources(), R.drawable.tank_right);
}
cursor = BitmapFactory.decodeResource(getResources(), R.drawable.cursor);
frameWidth = frame.getWidth();
frameHeight = frame.getHeight();
cursorHeight = cursor.getHeight();
}
public void determinePointers(int x, int y){
framePts.setOrigin(x-frameWidth/2, y-frameHeight/2);
cursorPts.setOrigin(x-frameWidth/2, y-frameHeight/2);
}
@Override
public boolean onTouchEvent(MotionEvent e){
int x = 0;
int y = 0;
Log.d("TouchUI", ">>>>> " + whoAmI);
if(e.getAction() == MotionEvent.ACTION_DOWN){
determinePointers(x,y);
pointerDown = true;
}else if(e.getAction() == MotionEvent.ACTION_UP){
pointerDown = false;
}else if(e.getAction() == MotionEvent.ACTION_MOVE){
dy = (int)e.getY()-framePts.getY();
if(dy <= 0){
dy=0;
}else if(dy+cursorHeight/2 >= frameHeight){
dy=frameHeight;
}
sendMotorSpeed(dy);
}
return true;
}
public void sendMotorSpeed(int dy){
float motor = dy;
motor-=frameHeight;
motor*=-1;
motor = (motor/frameHeight)*255;
PacketController.updateMotorSpeeds(whoAmI, (int)motor);
}
public void onDraw(Canvas canvas){
if(pointerDown){//twoDown){
canvas.drawBitmap(frame, framePts.getX(), framePts.getY(), null);
canvas.drawBitmap(cursor, cursorPts.getX(), (cursorPts.getY()+dy), null);
}
invalidate();
}
private class MyPoints{
private int x = -100;
private int y = -100;
private int deltaY = 0;;
public MyPoints(){
this.x = 0;
this.y = 0;
}
public int getX(){
return this.x;
}
public int getY(){
return this.y;
}
public void setOrigin(int x, int y){
this.x = x;
this.y = y;
}
public int getDeltaY(){
return deltaY;
}
public void setDeltaY(int newY){
deltaY = (newY-y);
Log.d("TouchUI", "DY: " + deltaY);
}
}
}
Main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parentLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.robota.android.TouchUI xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/leftTouchUI"
android:background="#0000"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_weight="1">
</com.robota.android.TouchUI>
<com.robota.android.TouchUI xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rightTouchUI"
android:background="#0000"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_weight="1">
</com.robota.android.TouchUI>
</LinearLayout>
RobotController.java (Haupt-Activity-Klasse)
package com.robota.android;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
public class RobotController extends Activity {
//Tag used to keep track of class in the Log
private static final String TAG = "robotController_new";
//Boolean to debugging
private static final boolean D = true;
//Intent request codes
private static final int DISCONNECT_DEVICE = 1;
private static final int CONNECT_DEVICE = 2;
private static final int REQUEST_ENABLE_BT = 3;
//Handler Codes
public static final int MESSAGE_READ = 1;
public static final int MESSAGE_WRITE = 2;
//Local Bluetooth Adapter
private BluetoothAdapter bluetoothAdapter = null;
//Bluetooth Discovery and Datahandler
private BluetoothComm btComm = null;
//Debug's TextView, this is where strings will be written to display
private TextView tv;
private ScrollView sv;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
if(D) Log.d(TAG, "++ON CREATE++");
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter == null){
if(D) Log.d(TAG, "NO BLUETOOTH DEVICE");
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_SHORT).show();
finish();
return;
}
PacketController.controller = this;
}
public void onStart(){
super.onStart();
if(D) Log.d(TAG, "++ON START++");
if(!bluetoothAdapter.isEnabled()){
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}else{
//Start BluetoothComm
if(btComm == null){
setupComm();
}
}
}
/**
* Creates new Bluetooth Communication
*/
private void setupComm(){
if(D) Log.d(TAG, "+++setupComm+++");
btComm = new BluetoothComm(this, handler);
}
private void connectDevice(Intent data){
if(D) Log.d(TAG, "+++connectDevice+++");
String addr = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(addr);
if(D) Log.d(TAG,"REMOTE ADDR: "+ addr);
btComm.connect(device);
}
private void disconnectDevice(){
if(D) Log.d(TAG, "---disconnectDevice---");
if(btComm.getState() == btComm.STATE_CONNECTED){
btComm.disconnect();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
//super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent serverIntent = null;
switch(item.getItemId()){
case R.id.insecure_connect_scan:
//Launch the DeviceListActivity to see devices and do scan
serverIntent = new Intent(this, DeviceListActivity.class);
try{
startActivityForResult(serverIntent, CONNECT_DEVICE);
}catch(ActivityNotFoundException activityNotFound){
Log.e(TAG, "Could not start DeviceListActivity(Insecure)");
}
return true;
}
return false;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
switch(requestCode){
case CONNECT_DEVICE:
if(resultCode == Activity.RESULT_OK){
connectDevice(data);
}
break;
case DISCONNECT_DEVICE:
if(resultCode == Activity.RESULT_OK){
disconnectDevice();
}
break;
}
}
public Handler getHandler(){
return this.handler;
}
public BluetoothComm getBtComm(){
return this.btComm;
}
//The Handler that gets information back from the BluetoothChatService
private final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(D) Log.d(TAG, "check message");
switch (msg.what) {
case MESSAGE_READ:
if(D) Log.d(TAG, "trying to read message");
byte[] readBuf = (byte[]) msg.obj;
//construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
if(D) Log.d(TAG, "bytes: " + readBuf + " arg1: " + msg.arg1 + " Message: " + readMessage);
tv.append(readMessage);
break;
case MESSAGE_WRITE:
if(D) Log.d(TAG, "trying to send message");
String sendMessage = new String(String.valueOf(msg.obj));
}
}
};
}
Andere Klassen nicht aufgeführt, ich konnte nicht glauben, gebraucht zu werden, aber wenn Sie gebraucht werden, lasst es mich bitte wissen.
Jede Hilfe ist sehr willkommen
InformationsquelleAutor heater | 2011-05-31
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie gehen zu müssen, speichern Sie die pointerId ist von jedem Punkt, und vergleichen Sie Sie mit den neuen Id ' s gegeben, der mit jeder MotionEvent. Es ist etwas schwierig zu erklären, also werde ich Sie auf dieser ADB-Post, das erklärt es viel besser als ich es könnte. Lange Geschichte kurz? Multitouch kann tricksy, aber es ist nicht so schlimm, wie es auf den ersten Blick aussieht.
Gut, der index ändern kann. Die Id wird ausdauernd zu verwenden, so dass zu finden. Finden Sie heraus, was den Index für einen gegebenen Zeiger ist für die -aktuelle - MotionEvent nur verwenden findPointerIndex(id). Stellen Sie sicher, Lesen Sie den Abschnitt "Index vs-Id" im link, den ich gab.
Okay, der Artikel hilft mir dabei, langsam zu verstehen, was ich aber nicht bekommen bin ist, soll ich das willkürlich wählen Sie eine Zeiger-ID für jeden touch? Diese Linie mActivePointerId = ev.getPointerId(0);, verwirrt mich, weil 0 ist bezogen auf den ersten finger nach unten oder ist es eine Nummer, die der Programmierer ausgewählt, die den ersten finger nach unten? Bedeutet das, dass meine anderen finger nach unten muss 1 sein und möglicherweise meinen Dritten finger wäre eine 2? Vielen Dank im Voraus.
Nein, es ist nicht willkürlich. Die Linie, die Sie darauf hingewiesen, innerhalb der ACTION_DOWN Fall. ACTION_DOWN wird nur ausgelöst, wenn Sie den ersten finger nach unten drückt. Zweite, etc, wirft einen ACTION_POINTER_DOWN statt. Also, er ist mit 0 da, weil er weiß, dass es nur einen index in der Falle, und er will, dass die erste(und einzige). Was Sie tun sollten, ist, speichern Sie die ID für jeden finger jedes mal, wenn Sie ein DOWN-Art-Aktion. Wenn du einen MOVE-Typ UP-Typ, Aktion, ausführen, eine findPointerIndex() für jede gespeicherte ID. Dann haben Sie einen index aus, den Sie verwenden können, zu nennen getX/Y(index). Vergessen Sie nicht, entfernen Sie die ID auf Veranstaltungen auch.
Ok, ich bin wirklich sorry, aber ich bin mit Recht ein wenig Mühe Verständnis noch, ich danke Ihnen so sehr für Ihre Geduld. Die findPointerIndex() erfordert eine ID um einen index korrekt? Aber dann ist die Methode getPointerId() erfordert einen index? Dies scheint sehr Runder zu mir... :P. Also tun, ich muss nur noch eine ID zuweisen meinen ersten finger (ex: 0) und weisen eine ID zu meiner zweiten finger (ex: 1)? Oder welche Methode muss ich verwenden, um die anfängliche ID des touch, ohne die Notwendigkeit für einen index? Wieder einmal, vielen Dank für Ihre Geduld mit diesem Zeug.
InformationsquelleAutor Geobits