Отримання координат перегляду щодо кореневого макета


Відповіді:


138

Це одне рішення, хоча оскільки API змінюються з часом і можуть бути інші способи цього, переконайтеся, що перегляньте інші відповіді. Один стверджує, що швидше, а інший - простіше.

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

Повідомте мене, якщо це працює.

Він повинен рекурсивно просто додавати верхню та ліву позиції від кожного батьківського контейнера. Ви також можете його реалізувати, Pointякщо хочете.


getRelativeLeft () для цього потрібно додати кастинг, але коли я додаю (View) або (кнопку) ((Object) myView.getParent ()). getRelativeTop (), це також не правильно
pengwang

Я зробив щось дуже схоже, але я перевірив кореневий вигляд getId == R.id.myRootView.
fhucho

1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv))); я отримую все 0; textView в макеті виглядає наступним чином <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

Такий усміхнений підхід (обчислюючи його вручну) працював для мене, тому я прийняв цю відповідь.
fhucho

3
андроїд апі вже забезпечує відносну координату до кореня. дивіться тут stackoverflow.com/a/36740277/2008214
carlo.marinangeli

155

Android API вже пропонує метод досягнення цього. Спробуйте це:

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;

Ось док


16
Це має бути прийнятою відповіддю. Немає можливості переповнення стека і немає можливості математичних помилок. Дякую!
GLee

Я погоджуюсь, це має бути прийнята відповідь - лише 92 голоси.
запаморочив

Я хотів знайти координати подання на панелі інструментів. Це єдиний метод, який послідовно працює для обліку Android: fitsSystemWindows та різних версій API від 19 до 27. Тож дякую! Це правильна відповідь.
Девід Ферран

Працював бездоганно
Рава

Працювало дуже добре, просто хочу зазначити, що parentViewGroupв ієрархії перегляду може бути будь-який батько, тому він прекрасно працює і для ScrollView.
Сіра Лам

93

Будь ласка, використовуйте view.getLocationOnScreen(int[] location);(див. Javadocs ). Відповідь знаходиться у цілому масиві (x = location[0]і y = location[1]).


13
Це повертає положення відносно екрана, а не до кореневого макета Діяльності.
fhucho

10
Існує також View.getLocationInWindow (int []), який повертає положення перегляду відносно вікна.
Рубікон

Скажіть, будь ласка, як саме цей метод працює. Він повертає порожнечу, як це робити, ми отримуємо вихідні або x, y значення перегляду на екрані
user1106888

6
Щоб отримати позицію щодо кореневого макета, просто зателефонуйте getLocationInWindow для кореневого макета та елемента та використовуйте силу віднімання. Це набагато простіше і, ймовірно, швидше, ніж прийнята відповідь.
Блейк Міллер

1
це лише місце, пов’язане з екраном. не корінь. прочитати тут відносно кореня: 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];

Спочатку я отримую кореневий макет, а потім обчислюю різницю координат з видом.
Ви також можете використовувати getLocationOnScreen()замість getLocationInWindow().


3
який вигляд масштабується і обертається?
ДКВ

Це єдина відповідь, яка працює на мене. На це слід прийняти відповідь
neoexpert

36

Не потрібно обчислювати це вручну.

Просто використовуйте getGlobalVisibleRect так:

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

Також зауважте, що для координат центру, а не чогось типу:

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

Ви можете просто зробити:

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

Дивлячись на андроїд-джерело, все getGlobalVisibleRectце globalOffset.set(-mScrollX, -mScrollY);так, щоб ви могли просто отримати ці значення, getScollX/Yякщо вам потрібні лише відносні кодинати.
Ксандер

2
На це слід прийняти відповідь. getLocationOnScreen працює так само, як і getGlobalVisibleRect. Але getGlobalVisibleRect надає трохи більше інформації, і не потрібно працювати з необробленими масивами. Тому я б пішов з getGlobalVisibleRect. Використання просте. Rect positionRect = новий Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. ура
JacksOnF1re

якщо якась частина дитини знаходиться поза, яка не враховуватиметься у цьому випадку. як вирішити такий випадок?
ДКВ

Чудова відповідь! Дуже дякую!
Рохіт Кумар

8

Ви можете використовувати `

view.getLocationOnScreen (int [] розташування)

; `щоб правильно встановити розташування свого перегляду.

Але є улов, якщо ви будете використовувати його до того, як макет був роздутий, ви отримаєте неправильне положення.

Вирішення цієї проблеми додає ViewTreeObserverтак: -

Декларуйте глобальний масив, щоб зберігати положення xy вашого представлення

 int[] img_coordinates = new int[2];

а потім додайте ViewTreeObserverдо свого батьківського макета, щоб отримати зворотний виклик для інфляції макета, і лише тоді отримаєте позицію перегляду, інакше ви отримаєте неправильні координати xy

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

а потім використовувати його так

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

3

Я написав собі два корисні методи, які, здається, працюють у більшості умов, обробляючи прокрутку, переклад та масштабування, але не обертання. Я зробив це, намагаючись використовувати offsetDescendantRectToMyCoords () у рамках, який мав непослідовну точність. У деяких випадках це спрацьовувало, але в інших дало неправильні результати.

"точка" - це поплавковий масив з двома елементами (координати x & y), "предка" - це група огляду десь над "нащадком" в ієрархії дерев.

Спочатку метод, який переходить від нащадкових координат до предка:

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

Далі зворотне, від предка до нащадка:

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

Скрізь, хтось все ще намагається це зрозуміти. Це, як ви отримаєте центр X і Y з view.

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

1

Я щойно знайшов відповідь тут

У ній написано: Можна отримати місце перегляду, скориставшись методами getLeft () та getTop (). Перший повертає ліву, або X, координату прямокутника, що представляє вид. Останній повертає верхню або Y координату прямокутника, що представляє вид. Ці методи повертають місце перегляду відносно його батьківського. Наприклад, коли getLeft () повертає 20, це означає, що представлення розташоване на 20 пікселів праворуч від лівого краю його прямого батьківства.

тому використовуйте:

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
Це дає розташування відносно безпосереднього батьківського виду, а не кореневого виду, який може бути батьківським батьком тощо.
Руперт Роунслі

який вигляд масштабується і обертається?
ДКВ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.