439

我正在尝试获取视图左上角的绝对屏幕像素坐标。getLeft()但是,我能找到的所有方法都getRight()不起作用,因为它们似乎都与视图的父级相关,因此给了我0. 这样做的正确方法是什么?

如果它有帮助,这是一个“把图片恢复秩序”的游戏。我希望用户能够绘制一个框来选择多个部分。我的假设是,最简单的方法是getRawX()往返getRawY()MotionEvent,然后将这些值与包含这些片段的布局的左上角进行比较。知道了棋子的大小,我就可以确定选择了多少棋子。我意识到我可以在 上使用getX()and ,但是因为它会返回一个相对位置,这使得确定哪些部分被选中变得更加困难。(并非不可能,我知道,但它似乎不必要地复杂)。getY()MotionEvent

编辑:这是我用来尝试获取容纳容器大小的代码,根据问题之一。TableLayout是包含所有拼图的桌子。

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
Log.d(LOG_TAG, "Values " + tableLayout.getTop() + tableLayout.getLeft());

编辑2:这是我尝试过的代码,遵循更多建议的答案。

public int[] tableLayoutCorners = new int[2];
(...)

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
tableLayout.requestLayout();
Rect corners = new Rect();
tableLayout.getLocalVisibleRect(corners);
Log.d(LOG_TAG, "Top left " + corners.top + ", " + corners.left + ", " + corners.right
            + ", " + corners.bottom);

cells[4].getLocationOnScreen(tableLayoutCorners);
Log.d(LOG_TAG, "Values " + tableLayoutCorners[0] + ", " + tableLayoutCorners[1]);

此代码是在所有初始化完成后添加的。图像已被划分为包含在TableLayout. Cells[0] 是左上角ImageView,我选择了 cells[4] 因为它在中间的某个地方,而且绝对不应该有 (0,0) 的坐标。

上面显示的代码在日志中仍然给我全0,我真的不明白,因为各种拼图都正确显示。(我为 tableLayoutCorners 和默认可见性尝试了 public int,两者都给出了相同的结果。)

我不知道这是否重要,但ImageViews 最初没有给出大小。ImageView当我给它一个要显示的图像时, s的大小由 View 在初始化期间自动确定。这是否会导致它们的值为 0,即使日志记录代码是在它们被赋予图像并自动调整大小之后?为了可能解决这个问题,我添加了tableLayout.requestLayout()如上所示的代码,但这并没有帮助。

4

10 回答 10

684

使用View.getLocationOnScreen()和/或getLocationInWindow()

于 2010-02-09T01:05:19.330 回答
169

接受的答案实际上并没有说明如何获取位置,所以这里有更多细节。您传入一个int长度为 2 的数组,这些值将替换为视图的 (x, y) 坐标(左上角)。

int[] location = new int[2];
myView.getLocationOnScreen(location);
int x = location[0];
int y = location[1];

笔记

  • getLocationOnScreen在大多数情况下,替换getLocationInWindow应该会产生相同的结果(请参阅此答案)。但是,如果您在像对话框或自定义键盘这样的较小窗口中,则需要选择更适合您需要的窗口。
  • (0,0)如果你调用这个方法,你会得到,onCreate因为视图还没有布局。您可以使用 aViewTreeObserver来监听布局何时完成,您可以获得测量的坐标。(见这个答案。)
于 2017-01-14T11:23:14.367 回答
103

首先,您必须获取视图的 localVisible 矩形

例如:

Rect rectf = new Rect();

//For coordinates location relative to the parent
anyView.getLocalVisibleRect(rectf);

//For coordinates location relative to the screen/display
anyView.getGlobalVisibleRect(rectf);

Log.d("WIDTH        :", String.valueOf(rectf.width()));
Log.d("HEIGHT       :", String.valueOf(rectf.height()));
Log.d("left         :", String.valueOf(rectf.left));
Log.d("right        :", String.valueOf(rectf.right));
Log.d("top          :", String.valueOf(rectf.top));
Log.d("bottom       :", String.valueOf(rectf.bottom));

希望这会有所帮助

于 2010-02-09T04:16:11.400 回答
49

使用全局布局监听器对我来说一直很有效。它的优点是能够在布局更改时重新测量事物,例如,如果某些内容设置为 View.GONE 或添加/删除子视图。

public void onCreate(Bundle savedInstanceState)
{
     super.onCreate(savedInstanceState);

     // inflate your main layout here (use RelativeLayout or whatever your root ViewGroup type is
     LinearLayout mainLayout = (LinearLayout ) this.getLayoutInflater().inflate(R.layout.main, null); 

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

               // measure your views here
          }
       }
     );

     setContentView(mainLayout);
 }
于 2012-11-06T22:56:24.440 回答
21

第一种方式:

Kotlin中,我们可以为视图创建一个简单的扩展:

fun View.getLocationOnScreen(): Point
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return Point(location[0],location[1])
}

并简单地获取坐标:

val location = yourView.getLocationOnScreen()
val absX = location.x
val absY = location.y

第二种方式:

第二种方法更简单:

fun View.absX(): Int
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return location[0]
}

fun View.absY(): Int
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return location[1]
}

并简单地得到绝对的 X byview.absX()和 Y byview.absY()

于 2019-03-04T08:25:06.197 回答
18

在 Romain Guy 的评论之后,这就是我修复它的方法。希望它会帮助其他遇到此问题的人。

我确实试图在它们被布置在屏幕上之前获得视图的位置,但这种情况并不明显。这些行是在初始化代码运行后放置的,所以我认为一切都准备好了。但是,这段代码仍然在 onCreate(); 通过试验 Thread.sleep() 我发现布局实际上直到 onCreate() 一直到 onResume() 完成执行后才最终确定。所以确实,代码在布局完成定位在屏幕上之前试图运行。通过将代码添加到 OnClickListener(或其他一些侦听器),可以获得正确的值,因为它只能在布局完成后触发。


建议将以下行作为社区编辑:

请用onWindowfocuschanged(boolean hasFocus)

于 2010-02-09T21:16:45.083 回答
11

getLocationOnScreen()您可以使用或获取视图的坐标getLocationInWindow()

之后,x应该y是视图的左上角。如果您的根布局小于屏幕(如在对话框中),则使用getLocationInWindow将相对于其容器,而不是整个屏幕。

Java 解决方案

int[] point = new int[2];
view.getLocationOnScreen(point); // or getLocationInWindow(point)
int x = point[0];
int y = point[1];

注意:如果值始终为 0,您可能会在请求位置之前立即更改视图。

为确保视图有机会更新,请在使用以下命令计算视图的新布局后运行您的位置请求view.post

view.post(() -> {
    // Values should no longer be 0
    int[] point = new int[2];
    view.getLocationOnScreen(point); // or getLocationInWindow(point)
    int x = point[0];
    int y = point[1];
});

~~

Kotlin 解决方案

val point = IntArray(2)
view.getLocationOnScreen(point) // or getLocationInWindow(point)
val (x, y) = point

注意:如果值始终为 0,您可能会在请求位置之前立即更改视图。

为确保视图有机会更新,请在使用以下命令计算视图的新布局后运行您的位置请求view.post

view.post {
    // Values should no longer be 0
    val point = IntArray(2)
    view.getLocationOnScreen(point) // or getLocationInWindow(point)
    val (x, y) = point
}

我建议创建一个扩展函数来处理这个问题:

// To use, call:
val (x, y) = view.screenLocation

val View.screenLocation get(): IntArray {
    val point = IntArray(2)
    getLocationOnScreen(point)
    return point
}

如果您需要可靠性,还请添加:

view.screenLocationSafe { x, y -> Log.d("", "Use $x and $y here") }

fun View.screenLocationSafe(callback: (Int, Int) -> Unit) {
    post {
        val (x, y) = screenLocation
        callback(x, y)
    }
}
于 2019-11-04T03:58:48.620 回答
7

除了上述答案之外,关于您应该在何时何地打电话的问题getLocationOnScreen

对于与 , 相关的任何信息,view只有在视图在屏幕上布局(创建)后才可用。因此,要获取位置,请将您的代码放入其中,在布局view.post(Runnable)后调用,如下所示:view

view.post(new Runnable() {
            @Override
            public void run() {

               // This code will run when view created and rendered on screen

               // So as the answer to this question, you can put the code here
               int[] location = new int[2];
               myView.getLocationOnScreen(location);
               int x = location[0];
               int y = location[1];
            }
        });  
于 2020-04-30T10:08:59.607 回答
5

我的 utils 函数用于获取视图位置,它将返回一个Point对象x valuey value

public static Point getLocationOnScreen(View view){
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    return new Point(location[0], location[1]);
}

使用

Point viewALocation = getLocationOnScreen(viewA);
于 2017-10-12T07:08:50.900 回答
0

获取屏幕上的视图位置和尺寸

val viewTreeObserver: ViewTreeObserver = videoView.viewTreeObserver;

    if (viewTreeObserver.isAlive) {
        viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                //Remove Listener
                videoView.viewTreeObserver.removeOnGlobalLayoutListener(this);
                
                //View Dimentions
                viewWidth = videoView.width;
                viewHeight = videoView.height;

                //View Location
                val point = IntArray(2)
                videoView.post {
                    videoView.getLocationOnScreen(point) // or getLocationInWindow(point)
                    viewPositionX = point[0]
                    viewPositionY = point[1]
                }

            }
        });
    }
于 2020-04-09T07:46:49.283 回答