2010-02-08 14 views
306

Sto cercando di ottenere le coordinate pixel dello schermo assoluto nell'angolo in alto a sinistra di una vista. Tuttavia, tutti i metodi che riesco a trovare, ad esempio getLeft() e getRight(), non funzionano in quanto sembrano tutti relativi al genitore della vista, quindi mi danno 0. Qual è il modo corretto per farlo?Come ottenere le coordinate assolute di una vista

Se aiuta, questo è per un gioco "rimetti ordine in ordine". Voglio che l'utente sia in grado di disegnare una casella per selezionare più pezzi. La mia ipotesi è che il modo più semplice per farlo sia getRawX() e getRawY() dal MotionEvent e quindi confrontare questi valori con l'angolo in alto a sinistra del layout che contiene i pezzi. Conoscendo la dimensione dei pezzi, posso determinare quanti pezzi sono stati selezionati. Mi rendo conto che posso usare getX() e getY() su MotionEvent, ma come quello restituisce una posizione relativa che rende determinante quali pezzi sono stati selezionati più difficili. (Non impossibile, lo so, ma sembra inutilmente complicato).

Modifica: questo è il codice che ho utilizzato per cercare di ottenere le dimensioni del contenitore di attesa, come da una delle domande. TableLayout è il tavolo che contiene tutti i pezzi del puzzle.

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout); 
Log.d(LOG_TAG, "Values " + tableLayout.getTop() + tableLayout.getLeft()); 

Modifica 2: Ecco il codice che ho provato, seguendo più delle risposte suggerite.

public int[] tableLayoutCorners = new int[2]; 
(...) 

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout); 
tableLayout.requestLayout(); 
Rect corners = new Rect(); 
tableLayout.getLocalVisibleRect(corners); 
Log.d(LOG_TAG, "Top left " + corners.top + ", " + corners.left + ", " + corners.right 
      + ", " + corners.bottom); 

cells[4].getLocationOnScreen(tableLayoutCorners); 
Log.d(LOG_TAG, "Values " + tableLayoutCorners[0] + ", " + tableLayoutCorners[1]); 

Questo codice è stato aggiunto dopo che è stata eseguita l'inizializzazione. L'immagine è stata divisa in una serie di ImageViews (le celle [] array) contenute in un TableLayout. Celle [0] è in alto a sinistra ImageView e ho selezionato celle [4] poiché si trova da qualche parte nel mezzo e sicuramente non dovrebbero avere le coordinate di (0,0).

Il codice sopra riportato mi dà ancora tutti gli 0 nei log, che in realtà non capisco perché i vari pezzi del puzzle sono visualizzati correttamente. (Ho provato public int per tableLayoutCorners e visibilità predefinita, dando entrambi lo stesso risultato.)

Non so se questo è significativo, ma gli ImageView non hanno inizialmente una dimensione. La dimensione di ImageView s viene determinata automaticamente durante l'inizializzazione dalla vista quando viene visualizzata un'immagine da visualizzare. Questo potrebbe contribuire al fatto che i loro valori siano 0, anche se quel codice di registrazione è dopo che è stata loro assegnata un'immagine e si sono ridimensionati automaticamente? Per contrastarlo, ho aggiunto il codice tableLayout.requestLayout() come mostrato sopra, ma non è stato d'aiuto.

risposta

506

Utilizzare View.getLocationOnScreen() e/o getLocationInWindow().

+3

Ora che è il tipo di funzione I dovrebbe trovare Sfortunatamente, non devo usarlo correttamente. Mi rendo conto che è stato un bug noto che getLocationOnScreen fornisce un'eccezione di puntatore nullo in Android v1.5 (la piattaforma che sto codificando per), ma i test in v2.1 non hanno funzionato meglio. Entrambi i metodi mi hanno dato 0 per tutto. Ho incluso uno snippet di codice sopra. –

+61

È possibile solo richiamarlo * AFTER * è stato eseguito il layout. Stai chiamando il metodo prima che le viste siano posizionate sullo schermo. –

+4

Aha, hai ragione anche se non era ovvio che lo stavo facendo. Grazie! Per chiunque sia curioso di avere maggiori dettagli, ho aggiunto una risposta che spiega cosa intendo. –

52

In primo luogo si deve ottenere il rettangolo localVisible della vista

Per esempio:

Rect rectf = new Rect(); 

//For coordinates location relative to the parent 
anyView.getLocalVisibleRect(rectf); 

//For coordinates location relative to the screen/display 
anyView.getGlobalVisibleRect(rectf); 

Log.d("WIDTH  :", String.valueOf(rectf.width())); 
Log.d("HEIGHT  :", String.valueOf(rectf.height())); 
Log.d("left   :", String.valueOf(rectf.left)); 
Log.d("right  :", String.valueOf(rectf.right)); 
Log.d("top   :", String.valueOf(rectf.top)); 
Log.d("bottom  :", String.valueOf(rectf.bottom)); 

Spero che questo vi aiuterà

+2

Anche questo avrebbe dovuto funzionare ... Comunque mi sta dando dei valori pari a 0. Ho incluso uno snippet di codice sopra se questo ti aiuta a capire cosa ho sbagliato. Grazie ancora. –

+1

Vedere i miei altri commenti; Lo stavo chiamando accidentalmente prima che i Views avessero finito di sistemarsi. Funziona bene adesso grazie. –

+0

@Naveen Murthy fornisce le coordinate a una vista specifica, ho bisogno delle coordinate della vista cliccata nel layout radice .. – Aniket

15

seguente commento di Romain Guy, ecco come ho riparato. Speriamo che possa aiutare chiunque abbia avuto questo problema.

Stavo davvero cercando di ottenere le posizioni dei punti di vista prima che fossero disposti sullo schermo, ma non era affatto ovvio che stesse accadendo. Quelle linee erano state posizionate dopo l'esecuzione del codice di inizializzazione, quindi ho pensato che fosse tutto pronto. Tuttavia, questo codice era ancora in onCreate(); sperimentando con Thread.sleep() Ho scoperto che il layout non è in realtà finalizzato fino a dopo onCreate() fino a quando onResume() ha terminato l'esecuzione. Quindi, in effetti, il codice stava cercando di funzionare prima che il layout finisse di essere posizionato sullo schermo. Aggiungendo il codice a un OnClickListener (oa qualche altro listener) sono stati ottenuti i valori corretti perché potevano essere attivati ​​solo al termine del layout.


La riga sotto è stato suggerito come modifica comunità:

si prega di utilizzare onWindowfocuschanged(boolean hasFocus)

+0

Quindi intendete dire che setContentView (my_layout); non metterà tutte le viste. Tutte le viste saranno posizionate solo dopo che onCreate() è finito? – Ashwin

+5

Non proprio. Tutte le viste 'esistono' dopo 'setContentView (R.layout.something)', ma non sono state caricate visivamente. Non hanno una taglia o una posizione. Ciò non accade fino al termine del primo passaggio di layout, che avviene in un determinato momento nel futuro (generalmente dopo onResume()). –

35

Uso di un listener layout globale ha sempre funzionato bene per me. Ha il vantaggio di essere in grado di rimisurare le cose se il layout viene modificato, ad es. se qualcosa è impostato su View.GONE o le viste figlio vengono aggiunte/rimosse.

public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 

    // inflate your main layout here (use RelativeLayout or whatever your root ViewGroup type is 
    LinearLayout mainLayout = (LinearLayout) this.getLayoutInflater().inflate(R.layout.main, null); 

    // set a global layout listener which will be called when the layout pass is completed and the view is drawn 
    mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(
     new ViewTreeObserver.OnGlobalLayoutListener() { 
      public void onGlobalLayout() { 
       //Remove the listener before proceeding 
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 
        mainLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
       } else { 
        mainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
       } 

       // measure your views here 
      } 
     } 
    ); 

    setContentView(mainLayout); 
} 
+0

Non dimenticare di rimuovere OnGlobalLayoutListener all'interno (alla fine di) di onGlobalLayout() {...}. Inoltre, per sicurezza, controlla se ciò che è passato! = 0; l'ascoltatore può essere chiamato due volte, una volta con un valore di w = 0/h = 0, la seconda volta con i valori effettivi, corretti. – MacD

+0

Questo modo di gonfiare il layout principale e quindi usare 'setContentView()' ha causato un problema in uno speciale 'Activity' nella mia app! Quella era un'attività di dialogo ('windowFrame: @null, windowActionBar: false, windowIsFloating: true, windowNoTitle: true'). Il suo layout principale (un 'LinearLayout') non ha alcun figlio diretto con determinati' layout_width' (tutti erano 'match_parent' o' wrap_content'). –

0

utilizzare questo codice per trovare X esatto e cordinate Y:

int[] array = new int[2]; 
ViewForWhichLocationIsToBeFound.getLocationOnScreen(array); 
if (AppConstants.DEBUG) 
    Log.d(AppConstants.TAG, "array X = " + array[0] + ", Y = " + array[1]); 
ViewWhichToBeMovedOnFoundLocation.setTranslationX(array[0] + 21); 
ViewWhichToBeMovedOnFoundLocation.setTranslationY(array[1] - 165); 

ho aggiunto/sottratto alcuni valori di adattare il mio punto di vista. Si prega di fare queste linee solo dopo che la vista intera è stata gonfiata.

47

La risposta accettata non indicava in realtà come ottenere la posizione, quindi ecco alcuni dettagli in più. Si passa in una matrice int di lunghezza 2 e i valori vengono sostituiti con le coordinate della vista (x, y) (in alto a sinistra).

int[] location = new int[2]; 
myView.getLocationOnScreen(location); 
int x = location[0]; 
int y = location[1]; 

Note

  • Sostituzione getLocationOnScreen con getLocationInWindow dovrebbe dare gli stessi risultati nella maggior parte dei casi (vedi this answer).
  • Otterrete (0,0) se si chiama questo metodo in onCreate perché la vista non è stata ancora disposta. Puoi usare un ViewTreeObserver da ascoltare quando il layout è terminato e puoi ottenere le coordinate misurate. (Vedere this answer.)
2

La mia funzione utils per la vista ottenere la posizione, verrà restituito un oggetto Point con x value e y value

public static Point getLocationOnScreen(View view){ 
    int[] location = new int[2]; 
    view.getLocationOnScreen(location); 
    return new Point(location[0], location[1]); 
} 

Utilizzando

Point viewALocation = getLocationOnScreen(viewA); 
Problemi correlati