如何在Android的妥善处理触摸事件? [英] How do i handle touch events properly in android?

查看:245
本文介绍了如何在Android的妥善处理触摸事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

项目范围

当用户触摸屏幕的Andr​​oid用两个手指,画一个框架,在每个触摸位置有一个鼠标的每一帧。每个帧是一个自定义滑块光标会向上或向下移动。一路上涨将是100%,中间为0%,并一路下跌将是-100%。这将被用于控制小型马达,类似于罐车削,每个触摸控制一个单独的马达(通过蓝牙发送信号)。经过两个触摸,一切都画,我希望能够解除掉或者手指,但保留光标在什么都的位置是在最后,而其它手指可以自由移动的光标。当最后一个手指抬离,一切都隐藏,并重置为0%。

When a user touches the Android screen with two fingers, draw a "Frame" at each touch location with a "cursor" for each frame. Each frame is a custom slider that the cursor will move up and down. All the way up will be 100%, middle will be 0% and all the way down will be -100%. This will be used to control small motors, similar to tank turning, each touch controls a separate motor (sending signals over bluetooth). After a two touch and everything is drawn, I want to be able to lift off either finger, BUT keep the cursor at what ever location it was last at, while the other finger is free to move its cursor. When the last finger is lifted off, everything "hides" and resets to 0%.

功能通缉

  1. 在两指触摸,划下的触摸位置单独.pngs
  2. 帧和游标绘出后,跟踪他们在哪里相对于框架以确定的百分比。
  3. 如果手指被抬离,保持了手指光标放在最后一个已知的位置,而其它手指可以移动的光标。此外,如果将手指放回到向下它应该能够再次移动其光标。
  4. 如果两个手指抬离屏幕,隐藏一切,重比例为0%

功能获得

  • 我可以利用多点触控
  • 帧和游标
  • 位置和比例正常工作
  • 在光标移动不正确

将不起作用

  • 在我不确定我是否应该有一个处理两个触摸事件或一个自定义类,如果我应该有各自处理自己的触摸事件(我已经试过这两个,我得到任何​​真正的唯一办法自定义类的2个实例功能与1自定义类处理两个触摸事件,另一路并不如预期)
  • 工作
  • 当我只有1个自定义类,它的伟大工程,但我有它隐藏的一切,如果两个手指没有在屏幕上,而且我已经抬起手指从屏幕有时Android的寄存器,这导致了我很多时候,框架无再重新出现在不同的位置问题
  • 当我使用2个自定义类,我接触的每个自定义类将有自己的触摸事件,我不会担心多点触控,如果我分裂类均匀屏幕之间。这种情况并非如此,仍需要处理多点触控

有人能向我解释如何机器人处理的触摸事件。从我所做的一切,似乎如果我放下手指1,手指2,第一手指会注册一个ACTION_DOWN,第二个会注册一个ACTION_POINTER_2_DOWN,但如果我的生活离我的第一个手指,我的第二个手指被降级,现在我所有的第二根手指寄存器不与ACTION_POINTER_2的事件,而是将ACTION_DOWN,ACTION_UP等。这是正确的?

Can someone explain to me how android handles their touch events. from what I have done, it seems if i lay down finger 1, the finger 2, the first finger will register a "ACTION_DOWN" and the second will register a "ACTION_POINTER_2_DOWN", BUT if i life off my first finger, my second finger is "demoted" and now all of the events my second finger registers does not related to "ACTION_POINTER_2" and instead will be "ACTION_DOWN, ACTION_UP, etc". Is this correct?

TouchUI.java

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中

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(主营活动课)

RobotController.java (Main Activity Class)

    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));
        }
    }
};
}

任何其他类没有上市我不相信这是必要的,但如果需要他们,请让我知道。

Any other classes not listed I didn't believe needed to be, but if they are needed please let me know.

任何帮助是非常AP preciated

Any help is much appreciated

推荐答案

你将需要保存pointerId的每一个点,并将它们与新的ID的每个MotionEvent给出。这是有点棘手解释,所以我会指示你这的亚行邮,说明它更好的比我所能。长话短说?多点触控可以调皮,但它不是那么糟糕,因为它的外观乍一看。

You're going to need to save the pointerId's of each point and compare them to the new Id's given with each MotionEvent. It's slightly tricky to explain, so I'll point you to this ADB Post that explains it much better than I could. Long story short? Multitouch can be tricksy, but it's not as bad as it looks at first glance.

这篇关于如何在Android的妥善处理触摸事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆