2013-07-26 14 views
5

Mam aplikację, która używa razem SimpleOnScaleGestureListener i SimpleOnGestureListener. Za każdym razem, gdy robię zoom zbliżenia, uzyskuję oczekiwany efekt onScale, ale kiedy się podniosę, widzę dziwny onScroll, który ma pozycję początkową od początku powiększenia szczypcami i pozycję końcową od końca powiększenia szczypta. Moje pytanie brzmi: czy mogę zapobiec fałszywemu inSroll?Dziwne zdarzenie onScroll wyzwalane po zdarzeniu onScale

Oto kod:

@Override 
public boolean onTouchEvent(MotionEvent event) { 

    // Log every event. 
    Log.d(TAG, Here.at() + String.format("Event: %d, Time: %d X: %f, Y: %f", 
      event.getAction(), 
      event.getEventTime(), 
      event.getX(), 
      event.getY() 
      )); 

    boolean handled = mScaleDetector.onTouchEvent(event); // This appears to ALWAYS return true (online reference indicated that's what the Android code does). 

    handled |= mDetector.onTouchEvent(event); 

    handled |= super.onTouchEvent(event); 

    return handled; 
} 

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 

    @Override 
    public boolean onScaleBegin(ScaleGestureDetector detector) { 
     // This is required. If absent, the scale gesture never starts. 
     Log.d(TAG, "In onScaleBegin"); 
     mIgnoreNextDrag = true; 
     return true; 
    } 

    @Override 
    public boolean onScale(ScaleGestureDetector detector) { 
     Log.d(TAG, "In onScale"); 
     mTimeScale.doScale(detector.getScaleFactor(), detector.getFocusY()); 
     invalidate(); 
     return true; 
    } 

    @Override 
    public void onScaleEnd(ScaleGestureDetector detector) { 
     Log.d(TAG, "In onScaleEnd"); 
    } 

} 

private class GestureListener extends GestureDetector.SimpleOnGestureListener { 

    @Override 
    public boolean onScroll(MotionEvent me1, MotionEvent me2, float distanceX, float distanceY) { 

     Log.d(TAG, String.format("Motion Event 1: %d, Time: %d X: %f, Y: %f", 
       me1.getAction(), 
       me1.getEventTime(), 
       me1.getX(), 
       me1.getY() 
       )); 

     Log.d(TAG, String.format("Event 2: %d, Time: %d X: %f, Y: %f", 
       me2.getAction(), 
       me2.getEventTime(), 
       me2.getX(), 
       me2.getY() 
       )); 


     return true; 

    } 

    @Override 
    public boolean onSingleTapConfirmed(MotionEvent me) { 
     // Do tap processing. 
     return true; 
    } 

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
     // TODO: Future feature. 
     return true; 
    } 

    @Override 
    public boolean onDown(MotionEvent e) { 
     // This is required. If absent, the scroll gesture never starts. 
     return true; 
    } 

} 

oto LogCat:

13:06:05.885: D/my-tag(4140): In View.onTouchEvent, Event: 0, Time: 183279420 X: 171.761444, Y: 918.160767 
13:06:05.895: D/my-tag(4140): In View.onTouchEvent, Event: 261, Time: 183279420 X: 171.761444, Y: 918.160767 
13:06:05.895: D/my-tag(4140): In onScaleBegin 
13:06:05.895: I/ScaleGestureDetector(4140): TwScaleGestureDetector 
13:06:05.915: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279458 X: 171.761444, Y: 908.474365 
13:06:05.915: D/my-tag(4140): In onScale 
13:06:06.015: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279542 X: 174.964783, Y: 857.584717 
13:06:06.015: D/my-tag(4140): In onScale 
13:06:06.105: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279641 X: 232.242096, Y: 731.365662 
13:06:06.105: D/my-tag(4140): In onScale 
13:06:06.215: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279740 X: 313.564514, Y: 595.412964 
13:06:06.215: D/my-tag(4140): In onScale 
13:06:06.225: D/my-tag(4140): In View.onTouchEvent, Event: 6, Time: 183279751 X: 313.564514, Y: 595.412964 
13:06:06.225: D/my-tag(4140): In onScaleEnd 
13:06:06.245: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279774 X: 333.316528, Y: 487.607422 
13:06:06.245: D/my-tag(4140): In onScroll, me1: 0, Time: 183279420 X: 171.761444, Y: 918.160767 
13:06:06.245: D/my-tag(4140): In onScroll, me2 2: 2, Time: 183279774 X: 333.316528, Y: 487.607422 
13:06:06.255: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279784 X: 331.539551, Y: 488.496460 
13:06:06.265: D/my-tag(4140): In onScroll, me1: 0, Time: 183279420 X: 171.761444, Y: 918.160767 
13:06:06.265: D/my-tag(4140): In onScroll, me2 2: 2, Time: 183279784 X: 331.539551, Y: 488.496460 
13:06:06.275: D/my-tag(4140): In View.onTouchEvent, Event: 1, Time: 183279794 X: 331.539551, Y: 488.496460 

Widać, że pierwsze zdarzenie to pierwszy palec w dół (0 = ACTION_DOWN), następnie drugi palec w dół (261 = ACTION_POINTER_2_DOWN). Następnie widzimy wpis w dzienniku z wywołania onScaleBegin i log z detektora gestów skalowania (nie z mojego kodu). W tym momencie myślę, że mogę bezpiecznie założyć, że gest skali już się rozpoczął. Dokładnie zgodnie z oczekiwaniami.

Po nim następują cztery ruchy (2 = ACTION_MOVE), po których następuje natychmiast wpis dziennika z onScale. Jest to wciąż zgodne z oczekiwaniami.

Następnie widzimy wskaźnik w górę zdarzenia (6 = ACTION_POINTER_UP), a następnie wpis w dzienniku z onScaleEnd, nadal AOK! (Zauważ, że to 6, a nie 262, ponieważ podniosłem palce w takiej samej kolejności, w jakiej je odkładałem, więc wskaźnik 1 został podniesiony pierwszy, a nie wskaźnik 2.)

Teraz dziwny kawałek.

Widzimy zdarzenie przenoszenia, które zostanie pobrane przez onScroll w SimpleOnGestureListener. Pierwszy parametr me1 ma współrzędne xiy od pierwszego zderzenia przed wywołaniem gestu skalowania Drugi parametr me2 ma współrzędne, które najwyraźniej odzwierciedlają położenie po zatrzymaniu gestu skali.

W tym przykładzie występuje zdarzenie drugiego ruchu, które również interpretowane jest jako gest przewijania, ponownie z punktem początkowym skali wstępnej. Dzięki powyższemu kodowi różnie dostałbym 1, 2 lub brak zdarzeń przewijania po zbliżeniu z szczyptą.

(do wykończenia logcat, że ostateczna się impreza (1 = ACTION_UP) dla drugiego palca i dziennik idzie cicho.)

Więc robię to źle? Próbowałem tylko wywoływanie SimpleOnGestureListener, jeśli SimpleOnScaleGestureListener zwraca false z isInProgress, ale bez radości.

Wszelkie pomysły?

Z góry dziękuję i dziękuję wszystkim w społeczności za ogromną ilość informacji, które otrzymałem z tej strony przez lata!

Odpowiedz

6

Znalazłem również to dziwne zachowanie budując niestandardowy widok z możliwościami panoramowania/powiększania. Ale po zastanowieniu, oto moje rozumowanie:

W środowisku wielodotykowym , każdy palec jest rejestrowany, a ich ruchy są przetwarzane w sposób równoległy. Umożliwia to wykrywanie różnych zdarzeń dotykowych, które system może wysyłać za pomocą OnGestureListener i OnScaleGestureListener.

Dobrze, nic, czego jeszcze nie wiesz.

Teraz myślę różne zachowanie dwóch detektorów:

  • GestureDetector wykryje przewijania zdarzenie za pomocą przeciągania z tylko jednego palca wewnątrz granicach widocznego obszaru widoku. Jego wzór reaguje na: down - drag - up. Zdarzenia przewijania są generowane po wykryciu zdarzeń przeciągania.

  • ScaleGestureDetector wykrywa skalę o wydarzenia za pomocą dwóch jednoczesnych włóki opalanych dwoma palcami w multitouch środowiska. Jego wzór odpowiada: (down1 & down2) - (drag1 i/lub drag2) - (up1 lub up2).

A teraz pomyśl o niestandardowym widoku, w którym musisz tylko wykrywać zdarzenia przewijania (ignorując wszystkie inne). W takim przypadku zdarzenie przewijania musi zostać zwolnione na bok ze wszystkich innych względów, ponieważ wykonano jego wzorzec (przeciąganie w dół).

Po połączeniu tych dwóch detektorów, działają one niezależnie, więc pożary detektor skala pierwszy, ale po podniesieniu drugi palec, pożary detektor przewijania ponieważ wykrywa jeden palec, który jest przeciągając a kończąc wydarzenie!

Wniosek: zachowanie wydaje się rozsądne ... jednak Android mógł zapewnić wykrywacz krzyżowy dla jednoczesnej sytuacji.

Można po prostu wstawić wartość boolowską i rozwiązać problem. Miałem to zrobić w moim realizacji:

  • zadeklarować boolean nazwie scaling
  • Dokonaj onDown zdarzenie (na razie ACTION_DOWN), aby usunąć scaling
  • Dodać onScale wydarzenie ustawić scaling
  • DodaĂ onScroll wydarzenie nie przetwarzać zwój jeśli flaga scaling jest true

To już dla mnie zadziałało.

+0

Dobry plan, a dzięki za szczegółową odpowiedź. Wprowadziłem teraz coś bardzo podobnego, co pomaga mi zignorować zwój. –

Powiązane problemy