Могу ли я получить координаты x и y View относительно корневого макета моей Activity в Android?
Ответы:
Это одно из решений, хотя, поскольку 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
если хотите.
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;
Вот документ
parentViewGroup
может быть любой родительский элемент в иерархии представлений, поэтому он отлично работает и для ScrollView.
Пожалуйста, используйте view.getLocationOnScreen(int[] location);
(см. Javadocs ). Ответ находится в целочисленном массиве (x = location[0]
и y = location[1]
).
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()
.
Не нужно рассчитывать вручную.
Просто используйте 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
если вам нужны только относительные coodinates.
Вы можете использовать `
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];
Я написал себе два служебных метода, которые, кажется, работают в большинстве условий, обрабатывая прокрутку, перевод и масштабирование, но не вращение. Я сделал это после попытки использовать offsetDescendantRectToMyCoords () во фреймворке, который имел непоследовательную точность. В некоторых случаях это сработало, но в других дало неверные результаты.
«point» - это массив с плавающей запятой с двумя элементами (координаты x и y), «ancestor» - это группа просмотра где-то над «потомком» в древовидной иерархии.
Сначала метод, который переходит от координат потомка к предку:
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;
}
Если кто-то все еще пытается в этом разобраться. Это, как вы получите центр 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;
Я только что нашел здесь ответ
В нем говорится: можно получить местоположение представления, вызвав методы 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
Вы можете использовать следующее, чтобы узнать разницу между родителем и интересующим вас представлением:
private int getRelativeTop(View view) {
final View parent = (View) view.getParent();
int[] parentLocation = new int[2];
int[] viewLocation = new int[2];
view.getLocationOnScreen(viewLocation);
parent.getLocationOnScreen(parentLocation);
return viewLocation[1] - parentLocation[1];
}
Не забудьте вызвать его после отрисовки представления:
timeIndicator.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
final int relativeTop = getRelativeTop(timeIndicator);
});