获取 View 相对于根布局的坐标

我可以得到一个视图的 x 和 y 位置相对于我的活动在 Android 的根布局?

176395 次浏览

这是一种解决方案,但是由于 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实现它。

请使用 view.getLocationOnScreen(int[] location);(参见 Javadocs) ,答案是整数数组(x = location[0],y = location[1])。

不需要手工计算。

像这样使用 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();
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()

我刚刚找到了答案

上面写着: 通过调用 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

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;

这是 医生

我自己写了两个实用的方法,似乎在大多数情况下工作,处理滚动,平移和缩放,但不旋转。在尝试在框架中使用 offsetDescendantRectToMyCoord ()之后,我这样做了,因为它具有不一致的准确性。它在某些情况下起作用,但在另一些情况下产生了错误的结果。

“ point”是一个带有两个元素(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;
}

你可以用

GetLocationOnScreen (int [] location)

以获得正确的位置,你的观点。

但是有一个 接住,如果你使用它之前布局已经膨胀,你会得到错误的位置。

解决这个问题的方法是像这样添加 ViewTreeObserver:-

全局声明数组以存储视图的 x y 位置

 int[] img_coordinates = new int[2];

然后在父布局上添加 ViewTreeObserver以获得布局膨胀的回调,只有这样才能获取视图 否则你会得到错误的 x-y 坐标的位置

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

以防有人还在想办法。这就是得到 view的中心 X 和 Y 的方法。

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

您可以使用以下命令来获取父视图和感兴趣的视图之间的差异:

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