Cómo obtener las coordenadas absolutas de una vista

Estoy tratando de obtener las coordenadas de píxel de pantalla absolutas de la esquina superior izquierda de una vista. Sin embargo, todos los métodos que puedo encontrar como getLeft() y getRight() no funcionan, ya que todos parecen estar relacionados con el padre de la vista, dándome así 0 . ¿Cuál es la forma apropiada de hacer esto?

Si ayuda, esto es para un juego de ‘poner la imagen en orden’. Quiero que el usuario pueda dibujar un cuadro para seleccionar varias piezas. Mi suposición es que la manera más fácil de hacerlo es getRawX() y getRawY() del MotionEvent y luego comparar esos valores con la esquina superior izquierda del diseño que contiene las piezas. Conociendo el tamaño de las piezas, puedo determinar cuántas piezas se han seleccionado. Me doy cuenta de que puedo usar getX() y getY() en MotionEvent , pero como eso devuelve una posición relativa que hace que sea más difícil determinar qué piezas fueron seleccionadas. (No es imposible, lo sé, pero parece innecesariamente complicado).

Editar: Este es el código que utilicé para intentar obtener el tamaño del contenedor de retención, según una de las preguntas. TableLayout es la mesa que contiene todas las piezas del rompecabezas.

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

Editar 2: Aquí está el código que he intentado, siguiendo más de las respuestas sugeridas.

 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]); 

Este código fue agregado después de que toda la inicialización haya terminado. La imagen se ha dividido en una matriz de ImageViews (la matriz de celdas []) contenida dentro de un TableLayout . Cells [0] es la parte superior izquierda de ImageView , y elegí las celdas [4] ya que está en algún lugar en el medio y definitivamente no debería tener coordenadas de (0,0).

El código que se muestra arriba todavía me da todos los 0 en los registros, lo que realmente no entiendo porque las diversas piezas del rompecabezas se muestran correctamente. (Intenté public int para tableLayoutCorners y visibilidad predeterminada, ambos dando el mismo resultado).

No sé si esto es significativo, pero los ImageView s originalmente no tienen un tamaño. El tamaño de la ImageView s se determina automáticamente durante la inicialización por la Vista cuando le doy una imagen para mostrar. ¿Podría esto contribuir a que sus valores sean 0, a pesar de que ese código de registro es posterior a que se les haya dado una imagen y se hayan redimensionado automáticamente? Para potencialmente contrarrestar eso, agregué el código tableLayout.requestLayout() como se muestra arriba, pero eso no ayudó.

    Use View.getLocationOnScreen() y / o getLocationInWindow() .

    La respuesta aceptada en realidad no dice cómo obtener la ubicación, así que aquí hay un poco más de detalle. Usted transfiere una matriz int de longitud 2 y los valores se reemplazan por las coordenadas de la vista (x, y) (de la esquina superior izquierda).

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

    Notas

    • Reemplazar getLocationOnScreen con getLocationInWindow debería dar los mismos resultados en la mayoría de los casos (ver esta respuesta ). Sin embargo, si se encuentra en una ventana más pequeña, como un cuadro de diálogo o un teclado personalizado, utilice deberá elegir cuál se adapta mejor a sus necesidades.
    • Obtendrá (0,0) si llama a este método en onCreate porque todavía no se ha diseñado la vista. Puede usar un ViewTreeObserver para escuchar cuando el diseño está hecho y puede obtener las coordenadas medidas. (Ver esta respuesta )

    Primero debe obtener el rectángulo de vista local de la vista

    Por ejemplo:

     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)); 

    Espero que esto ayude

    Usar un oyente de diseño global siempre me ha funcionado. Tiene la ventaja de poder volver a medir las cosas si se cambia el diseño, por ejemplo, si algo se establece en View.GONE o las vistas secundarias se agregan / eliminan.

     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); } 

    Siguiendo el comentario de Romain Guy, así es como lo solucioné. Con suerte, ayudará a cualquier otra persona que también tenga este problema.

    De hecho, estaba tratando de obtener las posiciones de los puntos de vista antes de que se hayan presentado en la pantalla, pero no era del todo obvio que estaba sucediendo. Esas líneas habían sido colocadas después de que se ejecutara el código de iniciación, así que asumí que todo estaba listo. Sin embargo, este código todavía estaba en onCreate (); experimentando con Thread.sleep () Descubrí que el diseño no se finaliza hasta después de que onCreate () haya finalizado la ejecución de onResume (). De hecho, el código intentaba ejecutarse antes de que el diseño terminara de colocarse en la pantalla. Al agregar el código a OnClickListener (u otro Listener) se obtuvieron los valores correctos porque solo se podía disparar después de que el diseño había finalizado.


    La línea a continuación fue sugerida como una edición de comunidad:

    usa onWindowfocuschanged(boolean hasFocus)

    Mi función utils para obtener la ubicación de vista, devolverá un objeto Point con x value y

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

    Utilizando

     Point viewALocation = getLocationOnScreen(viewA); 

    Use este código para encontrar los cordinates X e Y exactos:

     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); 

    He agregado / restado algunos valores para ajustar mi vista. Haga estas líneas solo después de que se ha inflado toda la vista.