Obtención de coordenadas de vista relativas al diseño raíz


Respuestas:


138

Esta es una solución, aunque dado que las API cambian con el tiempo y puede haber otras formas de hacerlo, asegúrese de verificar las otras respuestas. Uno dice ser más rápido y otro dice ser más fácil.

private int getRelativeLeft(View myView) {
    if (myView.getParent() == myView.getRootView())
        return myView.getLeft();
    else
        return myView.getLeft() + getRelativeLeft((View) myView.getParent());
}

private int getRelativeTop(View myView) {
    if (myView.getParent() == myView.getRootView())
        return myView.getTop();
    else
        return myView.getTop() + getRelativeTop((View) myView.getParent());
}

Avísame si eso funciona.

Debe agregar recursivamente las posiciones superior e izquierda de cada contenedor principal. También puede implementarlo con un Pointsi lo desea.


getRelativeLeft () esto es necesario agregar conversión, pero cuando agrego (Ver) o (botón) ((Objeto) myView.getParent ()). getRelativeTop (), tampoco es correcto
pengwang

Hice algo muy similar pero verifiqué la vista raíz por getId == R.id.myRootView.
fhucho

1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv))); me sale todo es 0; textView en el diseño es el siguiente <TextView android: layout_width = "fill_parent" android: layout_height = "wrap_content" android: text = "@ string / hello" android: id = "@ + id / tv" android: layout_marginBottom = "69dip" android: layout_marginLeft = "69dip" />
pengwang

Un enfoque similar a este (calcularlo manualmente) funcionó para mí, así que acepté esta respuesta.
fhucho

3
la API de Android ya proporciona la coordenada relativa a la raíz. mira aquí stackoverflow.com/a/36740277/2008214
carlo.marinangeli

155

La API de Android ya proporciona un método para lograrlo. Prueba esto:

Rect offsetViewBounds = new Rect();
//returns the visible bounds
childView.getDrawingRect(offsetViewBounds);
// calculates the relative coordinates to the parent
parentViewGroup.offsetDescendantRectToMyCoords(childView, offsetViewBounds); 

int relativeTop = offsetViewBounds.top;
int relativeLeft = offsetViewBounds.left;

Aquí está el documento


16
Esta debería ser la respuesta aceptada. No hay posibilidad de un desbordamiento de pila, y no hay posibilidad de errores matemáticos. ¡Gracias!
GLee

Estoy de acuerdo, esta debería ser la respuesta aceptada: solo quedan 92 votos a favor.
aturdido el

Quería encontrar las coordenadas de una vista en la barra de herramientas. Este es el único método que funciona de manera consistente para dar cuenta de Android: fitsSystemWindows y varias versiones de API del 19 al 27. ¡Así que gracias! Esta es la respuesta correcta.
David Ferrand

Trabajó perfectamente
Rawa

Funcionó muy bien, solo quiero mencionar que parentViewGrouppuede ser cualquier padre en la jerarquía de vistas, por lo que también funciona perfectamente para ScrollView.
Sira Lam

93

Por favor, use view.getLocationOnScreen(int[] location);(ver Javadocs ). La respuesta está en la matriz de enteros (x = location[0]e y = location[1]).


13
Esto devuelve la posición relativa a la pantalla, no al diseño raíz de Activity.
fhucho

10
También hay View.getLocationInWindow (int []) que devuelve la posición de la vista en relación con la ventana.
Rubicon

¿Me puede decir exactamente cómo funciona este método? Devuelve un vacío sobre cómo obtener la salida o los valores x, y de una vista en la pantalla
usuario1106888

66
Para obtener la posición relativa al diseño raíz, simplemente llame a getLocationInWindow para el diseño raíz y el elemento, y use el poder de la resta. Es mucho más simple y probablemente más rápido que la respuesta aceptada.
Blake Miller

1
esta es solo la ubicación relacionada con la pantalla. No la raíz. lea aquí para relativo a la raíz: stackoverflow.com/a/36740277/2008214
carlo.marinangeli

36
View rootLayout = view.getRootView().findViewById(android.R.id.content);

int[] viewLocation = new int[2]; 
view.getLocationInWindow(viewLocation);

int[] rootLocation = new int[2];
rootLayout.getLocationInWindow(rootLocation);

int relativeLeft = viewLocation[0] - rootLocation[0];
int relativeTop  = viewLocation[1] - rootLocation[1];

Primero obtengo el diseño raíz y luego calculo la diferencia de coordenadas con la vista.
También puedes usar el en getLocationOnScreen()lugar de getLocationInWindow().


3
¿Cuál es la vista se escala y gira?
DKV

Esta es la única respuesta que me funciona. Esto debe ser aceptado respuesta
neoexpert

36

No es necesario calcularlo manualmente.

Simplemente use getGlobalVisibleRect así:

Rect myViewRect = new Rect();
myView.getGlobalVisibleRect(myViewRect);
float x = myViewRect.left;
float y = myViewRect.top;

También tenga en cuenta que para las coordenadas del centro, en lugar de algo como:

...
float two = (float) 2
float cx = myViewRect.left + myView.getWidth() / two;
float cy = myViewRect.top + myView.getHeight() / two;

Solo puedes hacer:

float cx = myViewRect.exactCenterX();
float cy = myViewRect.exactCenterY();

Mirando la fuente de Android todo lo que getGlobalVisibleRecthace es globalOffset.set(-mScrollX, -mScrollY);para que pueda obtener esos valores getScollX/Ysi solo necesita las coordenadas relativas.
Xander

2
Esto debe ser aceptado respuesta. getLocationOnScreen funciona tan bien como getGlobalVisibleRect. Pero getGlobalVisibleRect proporciona un poco más de información y no hay necesidad de trabajar con matrices sin procesar. Por lo tanto, iría con getGlobalVisibleRect. El uso es simple. Rect positionRect = nuevo Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. aplausos
JacksOnF1re 01 de

si alguna parte del niño está afuera, lo que no se tendrá en cuenta en este caso. ¿Cómo resolver tal caso?
DKV

¡Gran respuesta! Muchas gracias!
Rohit Kumar

8

Puedes usar `

view.getLocationOnScreen (int [] ubicación)

; `para obtener la ubicación de su vista correctamente.

Pero hay una trampa si lo usa antes de diseño ha sido inflado obtendrá una posición incorrecta.

La solución a este problema es agregar ViewTreeObserver así: -

Declare globalmente la matriz para almacenar la posición xy de su vista

 int[] img_coordinates = new int[2];

y luego agregue ViewTreeObserversu diseño principal para obtener una devolución de llamada para la inflación del diseño y solo entonces obtenga la posición de la vista, de lo contrario obtendrá coordenadas xy incorrectas

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

                            // measure your views here
                            fab.getLocationOnScreen(img_coordinates);
                        }
                    }
            );

y luego úsalo así

xposition = img_coordinates[0];
yposition =  img_coordinates[1];

3

Escribí dos métodos de utilidad que parecen funcionar en la mayoría de las condiciones, manejo de desplazamiento, traslación y escalado, pero no rotación. Hice esto después de intentar usar offsetDescendantRectToMyCoords () en el marco, que tenía una precisión inconsistente. Funcionó en algunos casos pero dio resultados incorrectos en otros.

"punto" es una matriz flotante con dos elementos (las coordenadas x e y), "ancestro" es un grupo de vista en algún lugar por encima del "descendiente" en la jerarquía del árbol.

Primero, un método que va de coordenadas descendientes a ancestro:

public static void transformToAncestor(float[] point, final View ancestor, final View descendant) {
    final float scrollX = descendant.getScrollX();
    final float scrollY = descendant.getScrollY();
    final float left = descendant.getLeft();
    final float top = descendant.getTop();
    final float px = descendant.getPivotX();
    final float py = descendant.getPivotY();
    final float tx = descendant.getTranslationX();
    final float ty = descendant.getTranslationY();
    final float sx = descendant.getScaleX();
    final float sy = descendant.getScaleY();

    point[0] = left + px + (point[0] - px) * sx + tx - scrollX;
    point[1] = top + py + (point[1] - py) * sy + ty - scrollY;

    ViewParent parent = descendant.getParent();
    if (descendant != ancestor && parent != ancestor && parent instanceof View) {
        transformToAncestor(point, ancestor, (View) parent);
    }
}

A continuación, el inverso, de antepasado a descendiente:

public static void transformToDescendant(float[] point, final View ancestor, final View descendant) {
    ViewParent parent = descendant.getParent();
    if (descendant != ancestor && parent != ancestor && parent instanceof View) {
        transformToDescendant(point, ancestor, (View) parent);
    }

    final float scrollX = descendant.getScrollX();
    final float scrollY = descendant.getScrollY();
    final float left = descendant.getLeft();
    final float top = descendant.getTop();
    final float px = descendant.getPivotX();
    final float py = descendant.getPivotY();
    final float tx = descendant.getTranslationX();
    final float ty = descendant.getTranslationY();
    final float sx = descendant.getScaleX();
    final float sy = descendant.getScaleY();

    point[0] = px + (point[0] + scrollX - left - tx - px) / sx;
    point[1] = py + (point[1] + scrollY - top - ty - py) / sy;
}

2

En caso de que alguien todavía esté tratando de resolver esto. Así es como obtienes el centro X e Y del view.

    int pos[] = new int[2];
    view.getLocationOnScreen(pos);
    int centerX = pos[0] + view.getMeasuredWidth() / 2;
    int centerY = pos[1] + view.getMeasuredHeight() / 2;

1

Acabo de encontrar la respuesta aquí

Dice: Es posible recuperar la ubicación de una vista invocando los métodos getLeft () y getTop (). El primero devuelve la coordenada izquierda o X del rectángulo que representa la vista. Este último devuelve la coordenada superior o Y del rectángulo que representa la vista. Estos dos métodos devuelven la ubicación de la vista en relación con su padre. Por ejemplo, cuando getLeft () devuelve 20, eso significa que la vista se encuentra a 20 píxeles a la derecha del borde izquierdo de su padre directo.

entonces usa:

view.getLeft(); // to get the location of X from left to right
view.getRight()+; // to get the location of Y from right to left

1
Esto le da la ubicación relativa al elemento primario inmediato de la vista, no a la vista raíz, que podría ser el elemento primario del elemento principal, etc ...
Rupert Rawnsley

¿Cuál es la vista se escala y gira?
DKV
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.