2011-12-09 14 views
13

Mam obraz wyświetlany dla użytkownika w mojej aplikacji na Androida.Uzyskaj współrzędne dotykowe względem widoku (odpowiednik ScreenToClient?)

Chcę móc określić, gdzie "dotykają" obrazu.

mogę łatwo dostać ekranu koordynuje poprzez wdrożenie OnTouchListener

private OnTouchListener image_Listener = new OnTouchListener(){ 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     if(event.getAction() == MotionEvent.ACTION_UP) { 
      float x = event.getX(); 
      float y = event.getY(); 
      return true; 
     } 
     return false; 
    } 
}; 

Jednakże są bezwzględne współrzędne. To, czego naprawdę potrzebuję, to funkcja konwersji tego na współrzędne w stosunku do widoku ..

Zrobiłem trochę kopania, ale nie mogę niczego odkryć, oprócz mnie, próbując wdrożyć metodę ScreenToClient siebie ..

Czy ktoś wie o dobrym rozwiązaniu tego problemu, czy też po prostu będę musiał wykonać własne?

Wygląda na to, że taka metoda jest dostępna - dlatego proszę.

Dziękuję wszystkim za poświęcony czas.

EDYCJA: Nie jestem tak pewien, że współrzędne nie są już względne w stosunku do widoku. Mogłem przysiąc, że współrzędne są absolutne, ale po jakimś majstrowaniu - mam rzeczy działające tak, jak się spodziewałem. Przepraszam za hałas.

Odpowiedz

20

Aby odpowiedzieć, dotknięcia są względne do widoku w pewien sposób. Tak, są to nieprzetworzone współrzędne ekranu dotyku. Ponieważ jednak zarejestrujesz zdarzenie dotyku w samym widoku, zostanie ono wywołane tylko wtedy, gdy użytkownik dotknie widoku. Oznacza to, że nawet jeśli współrzędne ekranu są współrzędnymi nieprzetworzonego ekranu, mieszczą się one w granicach samego widoku.

Jeśli chcesz uzyskać x/y współrzędne dotknął widzenia w stosunku do tylko sobie, to można subract lewa współrzędna z ekranu koordynuje i górna współrzędna z współrzędna y tak:

private OnTouchListener image_Listener = new OnTouchListener(){ 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     if(event.getAction() == MotionEvent.ACTION_UP) { 
      float screenX = event.getX(); 
      float screenY = event.getY(); 
      float viewX = screenX - v.getLeft(); 
      float viewY = screenY - v.getTop(); 
      return true; 
     } 
     return false; 
    } 
}; 

Dzięki temu, jeśli użytkownik dotknął ekranu 40 x pikseli, ale lewy margines został ustawiony na 10, wówczas viewX miałby być 30. Jeśli przesunąłeś widok o 40 pikseli i użytkownik dotknął tego samego miejsca w widoku nadal będzie 30.

To staje się nieco bardziej skomplikowane, jeśli włączysz dopełnienie jako wypełnienie w widoku nadal liczy się jako widok, mimo że nic nie wyświetla.

EDIT:

muszę podkreślić, że to, co Pierre powiedział, jest prawdą. Jeśli dotkniesz widoku, będzie on nadal otrzymywać zdarzenia dotykowe, dopóki palec nie zostanie podniesiony, nawet jeśli przeciągniesz palec poza granice widoku. Oznacza to, że ACTION_UP może otrzymać współrzędne ekranu dla twojego widoku, które nie mieszczą się w granicach.

+0

Dzięki za odpowiedź. – syllogism

+0

Przybywam to samo pytanie. Z samouczka te metody, takie jak view.getLeft(). "zwróć położenie widoku względem jego obiektu nadrzędnego." Często, ze skomplikowanym układem, badany widok nie jest bezpośrednim potomkiem widoku ekranu. Tak więc metoda wspomniana przez Deev nie może być stosowana zawsze. Masz jakiś nowy pomysł? – user1914692

+4

Hmm, znajduję sposób: Użyj View.getLocationOnScreen() i/lub getLocationInWindow(). – user1914692

2

Dotknij Współrzędne zdarzenia są względne do widoku, który odbiera zdarzenie. Nie są one jednak ograniczone do rozmiaru widoku, ponieważ użytkownik może oczywiście wysunąć się poza widok w tym samym ruchu.

Do czasu aktywowania ACTION_UP lub ACTION_CANCEL widok będzie nadal odbierać zdarzenia ruchu, nawet jeśli wskaźnik znajduje się poza widokiem.

Czy jesteś pewien, że słuchacz jest zarejestrowany we właściwym widoku?

+0

Tak, zarejestrowany we właściwym świetle .. Mam rzeczy pracują, jak się spodziewałem. Po prostu robiłem rzeczy trudniejsze, niż były potrzebne. Dziękuję za odpowiedź. – syllogism

18

Po prostu miałem ten sam problem i próbując rozwiązania DeeV zawsze otrzymywałem 0 z obu metod getLeft() i getTop(). Ponieważ zmiana układu nie była opcją (ponieważ myślę, że getTop/Left są względne tylko dla rodzica widoku) musiałem wymyślić, jak uzyskać absolutną pozycję widoku.

Oto podobne podejście z użyciem getLocationOnScreen (lokalizacja):

protected Point getRelativePosition(View v, MotionEvent event) { 
    int[] location = new int[2]; 
    v.getLocationOnScreen(location); 
    float screenX = event.getRawX(); 
    float screenY = event.getRawY(); 
    float viewX = screenX - location[0]; 
    float viewY = screenY - location[1]; 
    return new Point((int) viewX, (int) viewY); 
} 
+0

Ten działa, podczas gdy 'screenY - v.getTop()' nie (przynajmniej dla mnie) – 18446744073709551615

+0

v.getTop() też nie działał dla mnie. Ktoś ma jakiś pomysł, dlaczego? – eliasbagley

+0

@eliasbagley: v.getTop() jest względne względem rodzica v, podczas gdy screenY jest względne względem ekranu. Działa tylko wtedy, gdy rodzic przechodzi na górę ekranu. – user362178

Powiązane problemy