20

テスト用にズーム/ピンチ ジェスチャを生成しようとしています。Android API MotionEvent.obtain() を使用しようとしましたが、ズーム/ピンチ イベントを実装するのが難しいことがわかりました。

MotionEvent.obtainから API を参照しました。正しい方法を教えてください。

これが私の実装です:

//for zoom, we need four points coordinations: start0, start1, end0, end1

Instrumentation inst;

// action down event
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, 1, prop_start0, pointerCoords_start0, 0,  0, 0, 0, 0, 0, 0, 0 );
inst.sendPointerSync(event);

// action pointer 2 down event
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_POINTER_2_DOWN, 2, properties_start0_1, pointerCoords_start0_1, 0, 0, 0, 0, 0, 0, 0, 0);
inst.sendPointerSync(event);

// action move events
duration = 1000; //1000 ms
event_interval = 10;//time interval between consecutive events 10ms 
moveEventNum = duration / event_interval; 
stepx0 = (end0.x - start0.x)/moveEventNum;
stepy0 = (end0.y - start0.y)/moveEventNum;
stepx1 = (end1.x - start1.x)/moveEventNum;
stepy1 = (end1.y - start1.y)/moveEventNum;

move_event0= start0;
move_event1 = start1;
for ( int i = 0; i < moveEventNum; i++) {
       //  [generate middle points here ]
       mov_event0.x += stepx0;
       mov_event0.y += stepy0;
       mov_event1.x += stepx1;
       mov_event1.y += stepy1;

      eventTime += event_interval;

      event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 2, properties_move_event, pointerCoords_move_event0_1, 0, 0, 0, 0, 0, 0, 0, 0); 

     inst.sendPointerSync(event);
}

event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_POINTER_2_UP, 2, properties_end0_1, pointerCoords_end0_1, 0, 0, 0, 0, 0, 0, 0, 0);
inst.sendPointerSync(event);

event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, 1, end1, pointerCoords_end1, 0, 0, 0, 0, 0, 0, 0, 0 );
inst.sendPointerSync(event);
4

3 に答える 3

17

まあ、私は問題を見つけました。

問題:

get()APIを使用する場合、各イベントでポイントの圧力とサイズを設定する必要があります。

にとって

obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], 
android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int)

PointerCoords []では、圧力とサイズを1に設定する必要があります。デフォルト値は0です。

にとって

public static MotionEvent obtain (long downTime, long eventTime, int action,
         float x, float y, int metaState)

     Create a new MotionEvent, filling in a subset of the basic motion values. 
    Those not specified here are: device id (always 0), pressure and size (always 1), 
x and y precision (always 1), and edgeFlags (always 0).

since the default pressure and size are 1, so we don't need to set them.

ジェスチャーを作成するための私のヒント:

1.実際のジェスチャをシミュレートするため、実際のジェスチャシーケンスに従います

  • onTouchEvent()をオーバーライドして、アプリケーションが受信した実際のイベントを確認します。これらのイベントは、実際のユーザーのタッチイベントと生成されたタッチイベントの比較にも使用できます。ブラウザを例にとってみましょう。

    a)@Override public boolean onTouchEvent(MotionEvent event){Log.i( "WebView"、event.toString()+ event.getAction()); boolean rt = super.onTouchEvent(event); rtを返します。}

  • 手動で画面をタッチして、a)のonTouchEvent()から実際のジェスチャシーケンスを取得します。イベントを生成するときは、イベントシーケンスに従うことができます。-ジェスチャイベントシーケンスに従わない場合、インストルメントされたイベントが拒否される可能性があります。

  • これがズームジェスチャの有効なイベントシーケンスです(downTimeはすべてのイベントで同じです)

    私。1つの開始点のACTION_DOWN

    ii。2つの開始点のACTION_POINTER_2_DOWN

    iii.2つの中間点のACTION_MOVE

    iv。2つのエンドポイントのACTION_POINTER_2_UP

    v。1つのエンドポイントのACTION_UP

2.APIMotionEvent.obtainを正しく使用します

  • 最もよく使用されるget()APIは2つあります。

public static MotionEvent get(long downTime、long eventTime、int action、float x、float y、int metaState)

public static MotionEvent get(long、long、int、int、android.view.MotionEvent.PointerProperties []、android.view.MotionEvent.PointerCoords []、int、int、float、float、int、int、int、int)

最初のものは通常、フリング、スクロール、クリックなどのシングルポイントジェスチャに使用されます。この関数のパラメータ(圧力、サイズ、xPresion、yPresion)はすべて1に設定されています。

2つ目はより一般的なもので、マルチタッチイベントの生成に使用できます。2つ目は、各タッチポイントのpointerCoordsの圧力とサイズを1に設定する必要があります。

ズームジェスチャを生成する例を次に示します。

public static void generateZoomGesture(Instrumentation inst,
        long startTime, boolean ifMove, GestureInfo.Point startPoint1,
        GestureInfo.Point startPoint2, GestureInfo.Point endPoint1,
        GestureInfo.Point endPoint2, int duration) {

    if (inst == null || startPoint1 == null
            || (ifMove && endPoint1 == null)) {
        return;
    }

    long eventTime = startTime;
    long downTime = startTime;
    MotionEvent event;
    float eventX1, eventY1, eventX2, eventY2;

    eventX1 = startPoint1.x;
    eventY1 = startPoint1.y;
    eventX2 = startPoint2.x;
    eventY2 = startPoint2.y;

    // specify the property for the two touch points
    PointerProperties[] properties = new PointerProperties[2];
    PointerProperties pp1 = new PointerProperties();
    pp1.id = 0;
    pp1.toolType = MotionEvent.TOOL_TYPE_FINGER;
    PointerProperties pp2 = new PointerProperties();
    pp2.id = 1;
    pp2.toolType = MotionEvent.TOOL_TYPE_FINGER;

    properties[0] = pp1;
    properties[1] = pp2;

    //specify the coordinations of the two touch points
    //NOTE: you MUST set the pressure and size value, or it doesn't work
    PointerCoords[] pointerCoords = new PointerCoords[2];
    PointerCoords pc1 = new PointerCoords();
    pc1.x = eventX1;
    pc1.y = eventY1;
    pc1.pressure = 1;
    pc1.size = 1;
    PointerCoords pc2 = new PointerCoords();
    pc2.x = eventX2;
    pc2.y = eventY2;
    pc2.pressure = 1;
    pc2.size = 1;
    pointerCoords[0] = pc1;
    pointerCoords[1] = pc2;

    //////////////////////////////////////////////////////////////
    // events sequence of zoom gesture
    // 1. send ACTION_DOWN event of one start point
    // 2. send ACTION_POINTER_2_DOWN of two start points
    // 3. send ACTION_MOVE of two middle points
    // 4. repeat step 3 with updated middle points (x,y),
    //      until reach the end points
    // 5. send ACTION_POINTER_2_UP of two end points
    // 6. send ACTION_UP of one end point
    //////////////////////////////////////////////////////////////

    // step 1
    event = MotionEvent.obtain(downTime, eventTime, 
                MotionEvent.ACTION_DOWN, 1, properties, 
                pointerCoords, 0,  0, 1, 1, 0, 0, 0, 0 );

    inst.sendPointerSync(event);

    //step 2
    event = MotionEvent.obtain(downTime, eventTime, 
                MotionEvent.ACTION_POINTER_2_DOWN, 2, 
                properties, pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);

    inst.sendPointerSync(event);

    //step 3, 4
    if (ifMove) {
        int moveEventNumber = 1;
        moveEventNumber = duration / EVENT_MIN_INTERVAL;

        float stepX1, stepY1, stepX2, stepY2;

        stepX1 = (endPoint1.x - startPoint1.x) / moveEventNumber;
        stepY1 = (endPoint1.y - startPoint1.y) / moveEventNumber;
        stepX2 = (endPoint2.x - startPoint2.x) / moveEventNumber;
        stepY2 = (endPoint2.y - startPoint2.y) / moveEventNumber;

        for (int i = 0; i < moveEventNumber; i++) {
            // update the move events
            eventTime += EVENT_MIN_INTERVAL;
            eventX1 += stepX1;
            eventY1 += stepY1;
            eventX2 += stepX2;
            eventY2 += stepY2;

            pc1.x = eventX1;
            pc1.y = eventY1;
            pc2.x = eventX2;
            pc2.y = eventY2;

            pointerCoords[0] = pc1;
            pointerCoords[1] = pc2;

            event = MotionEvent.obtain(downTime, eventTime,
                        MotionEvent.ACTION_MOVE, 2, properties, 
                        pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);

            inst.sendPointerSync(event);
        }
    }

    //step 5
    pc1.x = endPoint1.x;
    pc1.y = endPoint1.y;
    pc2.x = endPoint2.x;
    pc2.y = endPoint2.y;
    pointerCoords[0] = pc1;
    pointerCoords[1] = pc2;

    eventTime += EVENT_MIN_INTERVAL;
    event = MotionEvent.obtain(downTime, eventTime,
                MotionEvent.ACTION_POINTER_2_UP, 2, properties, 
                pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
    inst.sendPointerSync(event);

    // step 6
    eventTime += EVENT_MIN_INTERVAL;
    event = MotionEvent.obtain(downTime, eventTime, 
                MotionEvent.ACTION_UP, 1, properties, 
                pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0 );
    inst.sendPointerSync(event);
}
于 2012-07-22T09:55:48.690 に答える
5

上記のコードを廃止されていない定数で動作させるため MotionEvent.ACTION_POINTER_DOWN + (pp2.id << MotionEvent.ACTION_POINTER_INDEX_SHIFT)に、MotionEvent.ACTION_POINTER_2_DOWN

したがって、次の行を置き換える必要がありました。

event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_POINTER_2_DOWN, 2, プロパティ, pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);

event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_POINTER_DOWN + (pp2.id << MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2, プロパティ, pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);

于 2013-03-21T13:18:55.277 に答える