添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
20

More than 5 years have passed since last update.

posted at

updated at

Androidでマルチタッチを使う

Androidでマルチタッチを使う方法を記載します。

タッチイベントの取得

タッチパネルを触るとonTouchEvent()がコールされます。
Activity or Viewでこの関数をoverrideすることでイベントを取得できます。
イベントはonTouchEvent()の引数MotionEventに格納されます。

イベントには種別があり、これをアクションといいます。
アクションはgetActionMasked()で取得します。

アクションの種類

アクションには次のものがあります。

タッチしていない状態でタッチしたとき

  • ACTION_DOWN
  • 0x00000000
  • タッチしている状態でタッチしなくなったとき

  • ACTION_UP
  • 0x00000001
  • すでにタッチしている状態で追加タッチしたとき
    例えばある指でタッチしている状態で、別の指でタッチしたとき

  • ACTION_POINTER_DOWN
  • 0x00000005
  • 複数の指でタッチしている状態で、そのうち1つの指を離したときのイベント

  • ACTION_POINTER_UP
  • 0x00000006
  • タッチ中に指を動かした場合

  • ACTION_MOVE
  • 0x00000002
  • 何らかの要因でキャンセルされた場合、ACTION_UPと同じ扱いにした方がいい。

  • ACTION_CANCEL
  • 0x00000003
  • 複数タッチの識別方法 Pointer indexとData index

    複数のタッチがあるときに、それぞれのタッチを識別するために、
    タッチには識別子 Pointer index がついています。
    タッチ開始時(触った時)に付与されて、タッチ終了時(離したとき)になくなります。

    一方でMotionEvent内に格納されたデータには配列のindexがあります。
    これを Data index ということにします。

    少しわかりにくいので例で説明します。

    Data indexは配列のindexなので、0から始まります、1つずつ増加して、(Data配列サイズ-1)で終わります。
    Pointer indexはタッチの識別子です。複数の指で触ったり、離したりすることを考えると、順番はバラバラになることがあります。
    また、値が(Data配列サイズ-1)を超える場合もあります。x,yは各タッチの座標値です。

    Pointer index, 座標値の取得

    Pointer index,座標値の取得方法は次の通りです。

    // 注意 : 説明のための必要最小限のソースコードに切り出しているため、実行はできません。
    MotionEvent event;
    int count = event.getPointerCount();
    for (int i=0; i<count; i++) {
        int pid = event.getPointerId(i);
        float x = event.getX(i);
        float y = event.getY(i);
    

    タッチしている数(Data配列のサイズ)をgetPointerCount()で取得します。Data indexでループします。
    Pointer indexは引数をData indexとしてgetPointerId()で取得します。
    座標値はgetX(),getY()で取得します。

    Pointer indexを指定してData indexを取得する

    あるPointer indexが、どのData indexに対応しているかを知るにはfindPointerIndex(Pointer index)を使います。
    引数にPointer indexを指定すると戻り値にData indexが返ってきます。

    蓄積されたイベント

    処理負荷が増加すると、あるonTouchEvent()と次のonTouchEvent()の間に、
    複数回タッチイベントが発生することがあります。下図参照。

    この時、複数のタッチイベントはMotionEvent内に蓄積されます。
    後ろ側のonTouchEventで蓄積された(例ではA)タッチイベントと現在のタッチイベント(例ではB)が取得できます。

    蓄積されたタッチイベントの個数はgetHistorySize()で取得できます。
    例ではタッチイベントAが1つ蓄積されるので値1が取得されます。

    蓄積された座標データはgetHistoricalX(Data index, index), getHistoricalY(Data index, index)で取得できます。
    第2引数は0~(getHistorySize()-1)の値です。index値が小さいほど古いデータになります。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int count = event.getPointerCount();
        for (int i
    
    
    
    
        
    =0; i<count; i++) {
            float x = event.getX(i);
            float y = event.getY(i);
            int hsize = event.getHistorySize();
            for (int j=0; j<hsize; j++) {
                float hx = event.getHistoricalX(i, j);
                float hy = event.getHistoricalY(i, j);
        return true;
    サンプルソースコード
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action1 = event.getAction();
        int action2 = event.getActionMasked();
        int count = event.getPointerCount();
        Log.e("", "getAction=0x" + String.format("%04x", action1) + ",getActionMasked=0x" + String.format("%04x", action2)
            + ",getPointerCount=" + count);
        for (int i=0; i<count; i++) {
            int pid = event.getPointerId(i);
            int id = event.findPointerIndex(pid);
            if (id == -1)
                continue;
            float x = event.getX(id);
            float y = event.getY(id);
            float p = event.getPressure(id);
            float s = event.getSize(id);
            int hsize = event.getHistorySize();
            String line = "\t";
            line += "getPointerId=" + pid + ",";
            line += "getHistorySize=" + hsize + ",";
            for (int j=0; j<hsize; j++) {
                float hx = event.getHistoricalX(id, j);
                float hy = event.getHistoricalY(id, j);
                float hp = event.getHistoricalPressure(id, j);
                float hs = event.getHistoricalSize(id, j);
                line += "x=" + String.format("%.2f", hx) + ",";
                line += "y=" + String.format("%.2f", hy) + ",";
                line += "p=" + String.format("%.4f", hp) + ",";
                line += "s=" + String.format("%.4f", hs) + ",";
            line += "x=" + String.format("%.2f", x) + ",";
            line += "y=" + String.format("%.2f", y) + ",";
            line += "p=" + String.format("%.4f", p) + ",";
            line += "s=" + String.format("%.4f", s) + ",";
            Log.e("", line);
        return true;
        //return super.onTouchEvent(event);
    Appendix
    getAction()とgetActionMasked()の違い
    

    getAction()とgetActionMasked()の違いを説明します。

    シングルタッチの場合、両者で取得されるイベントは同じになります。
    マルチタッチの場合、違いがあります。
    getAction()で取得されるイベントにはPointer indexが付加されます。
    getActionMasked()で取得されるイベントはPointer indexがマスクされたものです。

    具体例で説明します。

    シングルタッチでタップしたときのアクションです。
    双方同じ値が取得されます。

    D/: getAction=0x0000,getActionMasked=0x0000
    D/: getAction=0x0002,getActionMasked=0x0002
    D/: getAction=0x0002,getActionMasked=0x0002
    D/: getAction=0x0002,getActionMasked=0x0002
    D/: getAction=0x0001,getActionMasked=0x0001
    

    マルチタッチの例として、
    1本目の指でタッチ後、2本目の指でタッチし、指2→指1の順番で指を離したときのアクションで説明します。

    2本目をタッチしたときと、2本目を離したとき(*箇所)、
    getAction()とgetActionMasked()で取得されるアクションに違いがあることが分かります。
    getAction()で取得されるアクションにはPointer indexも一緒に渡されます。
    具体的には2本目の指をタッチしたとき、アクションは0x0105となり0x01の部分は2本目を表します。
    getActionMasked()が返すアクションはPointer indexがマスクされたものになります。

    D/: getAction=0x0000,getActionMasked=0x0000
    D/: getAction=0x0002,getActionMasked=0x0002
    D/: getAction=0x0002,getActionMasked=0x0002
    D/: getAction=0x0105,getActionMasked=0x0005(*)
    D/: getAction=0x0002,getActionMasked=0x0002
    D/: getAction=0x0002,getActionMasked=0x0002
    D/: getAction=0x0106,getActionMasked=0x0006(*)
    D/: getAction=0x0001,getActionMasked=0x0001
    

    Register as a new user and use Qiita more conveniently

    1. You get articles that match your needs
    2. You can efficiently read back useful information
    What you can do with signing up
    20