2013-07-19 41 views
10

Ho un layout semplice:Strano View.getHitRect() comportamento

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

<Button 
    android:id="@+id/button1" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="Button" /> 

<Button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:onClick="animate" 
    android:text="animate" /> 

</LinearLayout> 

e nella mia attività sto stampando colpo rect del pulsante dopo aver cambiato la sua posizione y:

public class MainActivity extends Activity { 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
} 

public void animate(View view) { 
    printHitRect(); 
    findViewById(R.id.button1).setY(50); 
    printHitRect(); 
} 
private void printHitRect() { 
    Rect rect = new Rect(); 
    findViewById(R.id.button1).getHitRect(rect); 
    Log.d(">>button1 hit rect", rect.flattenToString()); 
} 
} 

ATTESA DI USCITA

pulsante1 hit rect: 0 0 116 72

pulsante1 hit rect: 0 50 116 122

uscita effettiva

pulsante1 hit rect: 0 0 116 72

button1 colpo rect: -58 14 58 86

Qualcuno può spiegare questa uscita, sto facendo qualcosa di sbagliato o è un bug? Fondamentalmente sto usando questo getHitRect() nella mia personalizzata ViewGroup per rilevare quale utente figlio ha toccato. C'è un modo migliore per ottenere il bambino in un punto particolare, può essere una funzione come getChildAt(x, y)?

Invece di setY(), ho provato setTranslateY(). Ho anche usato la libreria NineOldAndroid e il framework di animazione incorporato. Lo stesso comportamento può essere visto se utilizzo findViewById(R.id.button1).animate().y(50) anziché setY().

UPDATE:

ho finito per scrivere metodo di utilità utilizzando la libreria nineoldandroid che sta lavorando ora:

private static void getHitRect(View v, Rect rect) { 
    rect.left = (int) com.nineoldandroids.view.ViewHelper.getX(v); 
    rect.top = (int) com.nineoldandroids.view.ViewHelper.getY(v); 
    rect.right = rect.left + v.getWidth(); 
    rect.bottom = rect.top + v.getHeight(); 
} 

risposta

8

getHitRect() aveva un bug e non si applicherebbe trasforma correttamente. Abbiamo risolto questo bug internamente e la correzione sarà resa disponibile nella prossima versione pubblica di Android.

+8

Dal momento che questa risposta è stata fatta il 19 luglio 2013, sto supponendo che si stia riferendo ad Android 4.3 come "prossima versione". Questo significa che il metodo, getHitRect() non è affidabile nelle versioni precedenti? – Saket

+0

@Saket Direi che è una buona ipotesi dato che ho un telefono qui che è bloccato su 4.1.2 (Xperia S) e le coordinate y che sto ottenendo non hanno molto senso, cioè in basso e in alto - bummer perché quella funzione rect mi avrebbe risparmiato un sacco di dolore ... – AgentKnopf

+0

@Zainodis Vedi l'aggiornamento dell'OP. Questo metodo dovrebbe funzionare bene :) – Saket

2

È possibile vieni colpito rect in questo modo:

public Rect getHitRect(View child){ 
    Rect frame = new Rect(); 
    frame.left = child.getLeft(); 
    frame.right = child.getRight(); 
    frame.top = child.getTop(); 
    frame.bottom = child.getBottom(); 
    return frame; 
} 
+0

questo non funziona come child.getLeft() restituisce il valore errato, la soluzione che l'interrogante ha scritto usando i lavori di nineoldandroid – 2cupsOfTech

1

Ecco una soluzione che non dipende da NineOldAndroids.

Se si segue il percorso di codice per NineOldAndroids percorso di codice alla fine si arriva qui su dispositivi pubblicare a nido d'ape: Github

private static void getHitRect(View v, Rect rect) { 
    rect.left = (int) (v.getLeft() + v.getTranslationX()); 
    rect.top = (int) (v.getTop() + v.getTranslationY()); 
    rect.right = rect.left + v.getWidth(); 
    rect.bottom = rect.top + v.getHeight(); 
} 
+0

Buona soluzione, devo solo aggiungere una piccola calibrazione 'rect.top - = dividerValue/2; rect.bottom + = dividerValue/2; 'come quando si utilizza un divisore più ampio tra gli elementi in listview, ci sono stati molti rilevamenti mancati di tocchi. – LadyWoodi