Obtendo as coordenadas da vista em relação ao layout raiz

142

Posso obter a posição x e y de uma visualização em relação ao layout raiz da minha atividade no Android?

fhucho
fonte

Respostas:

138

Esta é uma solução, embora, como as APIs mudem ao longo do tempo e que haja outras maneiras de fazê-lo, verifique as outras respostas. Um afirma ser mais rápido e outro afirma ser mais 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());
}

Deixe-me saber se isso funciona.

Recursivamente, basta adicionar as posições superior e esquerda de cada contêiner pai. Você também pode implementá-lo com um Pointse desejar.

ramblinjan
fonte
getRelativeLeft () isso é preciso acrescentar elenco, mas quando eu adiciono (View) ou (botão) ((Object) myView.getParent ()) getRelativeTop (), também não é certo.
Pengwang
Eu fiz algo muito semelhante, mas verifiquei a visualização raiz por getId == R.id.myRootView.
fhucho 2/09/10
1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv))); eu recebo tudo é 0; O textView no layout é o seguinte <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" />
escreveu
Uma abordagem semelhante a essa (calculando-a manualmente) funcionou para mim, então aceitei esta resposta.
Fhucho 5/05
3
a API do Android já fornece a coordenada relativa à raiz. veja aqui stackoverflow.com/a/36740277/2008214
carlo.marinangeli
155

A API do Android já fornece um método para conseguir isso. Tente o seguinte:

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;

Aqui está o documento

carlo.marinangeli
fonte
16
Essa deve ser a resposta aceita. Não há possibilidade de um estouro de pilha nem erros de matemática. Obrigado!
GLee
Eu concordo, esta deve ser a resposta aceita - faltam apenas 92 votos.
atordoado
Eu queria encontrar as coordenadas de uma exibição na barra de ferramentas. Este é o único método que funciona de maneira consistente para atender ao Android: fitsSystemWindows e várias versões da API de 19 a 27. Então, obrigado! Esta é a resposta certa.
David Ferrand
Funcionou perfeitamente
Rawa
Funcionou muito bem, só quero mencionar que parentViewGrouppode ser qualquer pai na hierarquia da exibição, portanto funciona perfeitamente para o ScrollView também.
Sira Lam
93

Por favor, use view.getLocationOnScreen(int[] location);(consulte Javadocs ). A resposta está na matriz inteira (x = location[0]e y = location[1]).

BinaryTofu
fonte
13
Isso retorna a posição rativa à tela e não ao layout raiz da atividade.
Fhucho 5/05
10
Há também View.getLocationInWindow (int []) que retorna a posição da exibição em relação à janela.
Rubicon 28/05
Você pode me dizer exatamente como esse método funciona. Ele retorna um vazio como é que vamos chegar a saída ou x, y valores de uma exibição na tela
user1106888
6
Para obter a posição em relação ao layout raiz, basta chamar getLocationInWindow para o layout raiz e o elemento e usar o poder da subtração. É muito mais simples e provavelmente mais rápido que a resposta aceita.
Blake Miller
1
este é apenas o local relacionado à tela. não é a raiz. leia aqui para em relação ao root: 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];

Primeiro, obtenho o layout raiz e depois calculo a diferença de coordenadas com a visualização.
Você também pode usar o em getLocationOnScreen()vez de getLocationInWindow().

Kerrmiter
fonte
3
qual é a vista é redimensionada e girada?
DKV
Esta é a única resposta que está funcionando para mim. Resposta deve ser aceita
neoexpert 24/02
36

Não há necessidade de calculá-lo manualmente.

Basta usar getGlobalVisibleRect assim:

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

Observe também que, para as coordenadas do centro, em vez de algo como:

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

Você pode apenas fazer:

float cx = myViewRect.exactCenterX();
float cy = myViewRect.exactCenterY();
Alta
fonte
Olhando para a fonte do Android, tudo o que getGlobalVisibleRectfaz é globalOffset.set(-mScrollX, -mScrollY);que você possa obter esses valores getScollX/Yse precisar apenas dos coordenados relativos.
Xander
2
Essa resposta deve ser aceita. getLocationOnScreen funciona bem como getGlobalVisibleRect. Mas getGlobalVisibleRect fornece um pouco mais de informação e não há necessidade de trabalhar com matrizes brutas. Portanto, eu iria com getGlobalVisibleRect. O uso é simples. Rect positionRect = novo Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. Cheers
JacksOnF1re
se alguma parte da criança estiver fora, a qual não será levada em consideração nesse caso. como resolver esse caso?
DKV
Ótima resposta! Muito obrigado!
Rohit Kumar
8

Você pode usar `

view.getLocationOnScreen (int [] local)

; `para obter a localização da sua visualização corretamente.

Mas há uma captura , se você usá-lo antes layout foi inflado você receberá posição errada.

A solução para este problema está adicionando ViewTreeObserverassim: -

Declare globalmente a matriz para armazenar a posição xy da sua visualização

 int[] img_coordinates = new int[2];

e adicione ViewTreeObserverseu layout pai para obter retorno de chamada para inflação do layout e só então buscar a posição da vista, caso contrário, você obterá coordenadas xy erradas

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

e depois use assim

xposition = img_coordinates[0];
yposition =  img_coordinates[1];
Hitesh Sahu
fonte
3

Escrevi para mim dois métodos utilitários que parecem funcionar na maioria das condições, lidando com rolagem, tradução e redimensionamento, mas não rotação. Fiz isso depois de tentar usar o offsetDescendantRectToMyCoords () na estrutura, que tinha precisão inconsistente. Funcionou em alguns casos, mas deu resultados errados em outros.

"point" é uma matriz flutuante com dois elementos (as coordenadas x e y), "ancestral" é um grupo de visualização em algum lugar acima do "descendente" na hierarquia da árvore.

Primeiro, um método que vai das coordenadas descendentes ao ancestral:

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

Em seguida, o inverso, do ancestral ao descendente:

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;
}
Alexander Hugestrand
fonte
2

Caso alguém ainda esteja tentando descobrir isso. É assim que você obtém o centro X e Y do view.

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

Acabei de encontrar a resposta aqui

Ele diz: É possível recuperar a localização de uma exibição invocando os métodos getLeft () e getTop (). O primeiro retorna a coordenada esquerda, ou X, do retângulo que representa a vista. O último retorna a coordenada superior, ou Y, do retângulo que representa a vista. Esses métodos retornam o local da visualização em relação ao pai. Por exemplo, quando getLeft () retorna 20, isso significa que a exibição está localizada 20 pixels à direita da borda esquerda de seu pai direto.

então use:

view.getLeft(); // to get the location of X from left to right
view.getRight()+; // to get the location of Y from right to left
donmj
fonte
1
Isto dá a localização em relação ao pai imediato do ponto de vista, não a exibição de raiz, o que poderia ser o pai do pai etc ...
Rupert Rawnsley
qual é a vista é redimensionada e girada?
DKV