2015-05-04 12 views
13

Mam bardzo podobny problem described here, z wyjątkiem tego, że zamiast używać ScaleAnimation, pozwalam na przybliżenie/przesuwanie w moim RelativeLayout.Skalowanie/przekształcanie obrazu w systemie Android nie zmienia obszaru klikalnego

Zoom/panoramowanie działa idealnie, ale niezależnie od tego, w jaki sposób mój widok jest przesuwany/powiększany, obszar klikalny nie zmienia się wraz z reprezentacją wizualną. Oto co moja dispatchTouchEvent wygląda następująco:

@Override 
public boolean dispatchTouchEvent(MotionEvent ev) { 
    if (mScaleGestureDetector != null && mGestureDetector != null) { 
     mScaleGestureDetector.onTouchEvent(ev); 
     mGestureDetector.onTouchEvent(ev); 
    } 

    final int action = ev.getAction(); 
    switch (action & MotionEvent.ACTION_MASK) { 
     case MotionEvent.ACTION_DOWN: { 
      final float x = ev.getX(); 
      final float y = ev.getY(); 

      mLastTouchX = x; 
      mLastTouchY = y; 
      mActivePointerId = ev.getPointerId(0); 
      break; 
     } 

     case MotionEvent.ACTION_MOVE: { 
      final int pointerIndex = ev.findPointerIndex(mActivePointerId); 
      final float x = ev.getX(pointerIndex); 
      final float y = ev.getY(pointerIndex); 

      // Only move if the ScaleGestureDetector isn't processing a gesture. 
      if (!mScaleGestureDetector.isInProgress() && mScaleFactor > 1f) { 
       final float dx = x - mLastTouchX; 
       final float dy = y - mLastTouchY; 

       float newPosX = mPosX + dx; 
       float newPosY = mPosY + dy; 
       if (isCoordinateInBound(newPosX, mScreenSize.x)) 
        mPosX = newPosX; 
       if (isCoordinateInBound(newPosY, mScreenSize.y)) 
        mPosY = newPosY; 

       invalidate(); 
      } 

      mLastTouchX = x; 
      mLastTouchY = y; 

      break; 
     } 

     case MotionEvent.ACTION_UP: { 
      mActivePointerId = INVALID_POINTER_ID; 
      break; 
     } 

     case MotionEvent.ACTION_CANCEL: { 
      mActivePointerId = INVALID_POINTER_ID; 
      break; 
     } 

     case MotionEvent.ACTION_POINTER_UP: { 
      final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
      final int pointerId = ev.getPointerId(pointerIndex); 
      if (pointerId == mActivePointerId) { 
       final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
       mLastTouchX = ev.getX(newPointerIndex); 
       mLastTouchY = ev.getY(newPointerIndex); 
       mActivePointerId = ev.getPointerId(newPointerIndex); 
      } 
      break; 
     } 
    } 

    return super.dispatchTouchEvent(ev); 
} 

i mojego dispatchDraw:

protected void dispatchDraw(Canvas canvas) { 
    canvas.save(Canvas.MATRIX_SAVE_FLAG); 
    canvas.translate(mPosX, mPosY); 

    canvas.scale(mScaleFactor, mScaleFactor); 
    super.dispatchDraw(canvas); 
    canvas.restore(); 
} 

Jak zmodyfikować obszar klikalny odpowiednio do zmodyfikowanej skali/transformacji płótnie?

Odpowiedz

9

Ponieważ jesteś już onverriding dispatchTouchEvent, można spróbować to:

  1. ręcznie oceniać każdą MotionEvent rozważając aktualny zoom/pan transformacji; można utworzyć nowyMotionEvent (nazwijmy go FakeMotionEvent) stosując odwrotnej zoom/pan transformację do oryginalnego MotionEventm.
  2. Sprawdź, czy FakeMotionEventprzechwytuje specyficzny Viewv; oznacza to, że użytkownik dotyka w położeniu, które reprezentuje widoczną dla użytkownika pozycję v.
  3. Jeśli FakeMotionEvent przechwytuje przeciwko, zużywają prąd MotionEvent i powołać v.dispatchTouchEvent(m);

TIP: Można użyć metody poniżej, aby ocenić, czy MotionEvent przechwytuje View z pewną tolerancją:

private boolean intercept(MotionEvent ev, View view, float boundingBoxTolerance){ 
    if (boundingBoxTolerance < 1.0f) { 
     boundingBoxTolerance = 1.0f; 
    } 
    try { 
     if (ev != null && view != null) { 
      int coords[] = new int[2]; 
      view.getLocationOnScreen(coords); 
      if (ev.getRawX() >= ((float)coords[0])/boundingBoxTolerance && ev.getRawX() <= coords[0] + ((float) view.getWidth()) * boundingBoxTolerance) { 
       if(ev.getRawY() >= ((float)coords[1])/boundingBoxTolerance && ev.getRawY() <= coords[1] + ((float) view.getHeight()) * boundingBoxTolerance) 
        return true; 
      } 
     } 
    } 
    catch (Exception e) {} 
    return false; 
} 
+1

Czy to oznacza, że ​​będę musiał sprawdzić wszystkie interaktywne widoki na moim układzie (Button, edittext itp.)? Wydaje się to raczej nieefektywne. – l46kok

+1

@ l46kok Tak wiem. To cena, którą musisz zapłacić, jeśli chcesz ręcznie obsługiwać wysyłkę zdarzeń dotykowych :) – bonnyz

0

Zgaduję, że używasz View Animations, wolę używać Property animations zamiast

fragment dokumentacji Androida (patrz podświetlone)

System widok animacja zapewnia możliwość tylko animować Zobacz przedmiotów, więc jeśli chce animować-view non obiektów, trzeba zaimplementuj własny kod, aby to zrobić. System animacji widoku jest również ograniczony przez to, że eksponuje tylko kilka aspektów obiektu View, na przykład, skalowanie i obracanie widoku, ale nie ma możliwości animacji, takiej jak skalowanie i obracanie widoku, ale nie.

Inną wadą systemu animacji widoku jest to, że zmodyfikowano tylko widok, w którym został narysowany widok, a nie sam widok.W przypadku instancji , jeśli animowałeś przycisk, aby poruszać się po ekranie, przycisk rysuje poprawnie, ale faktyczna lokalizacja, w której można kliknąć przycisk , przycisk się nie zmienia, więc musisz zaimplementować własną logikę, aby obsłużyć to urządzenie na .

Dzięki systemowi animacji nieruchomość, te ograniczenia są całkowicie usunięte i można animować każdy własność dowolnego obiektu (widoki i niebędących wyświetleń) i sam obiekt jest rzeczywiście zmodyfikowana. System animacji obiektu jest również bardziej niezawodny w sposobie realizacji animacji . Na wysokim poziomie można przypisać animatorów do właściwości , które mają zostać animowane, takich jak kolor, położenie lub rozmiar, a także mogą określać aspekty animacji, takie jak interpolacja i synchronizacja wielu animatorów.

Jednak system animacji widoku zajmuje mniej czasu, a do zapisywania wymaga mniej kodu. Jeśli animacja widoku zapewnia wszystko, co musisz zrobić, lub jeśli Twój istniejący kod działa już zgodnie z oczekiwaniami, nie musisz używać systemu animacji właściwości. To może również mieć sens, aby korzystać z obu systemów animacji dla różnych sytuacji , jeśli wystąpi przypadek użycia.