如何获取视图的绝对坐标
我正在尝试获取视图左上角的绝对屏幕像素坐标。但是,我能找到的所有方法(例如 getLeft()
和 getRight()
)都不起作用,因为它们似乎都与视图的父级相关,因此给出我0
。执行此操作的正确方法是什么?
如果有帮助的话,这是一个“将图片恢复正常”的游戏。我希望用户能够绘制一个框来选择多个部分。我的假设是,最简单的方法是从 MotionEvent
中获取 getRawX()
和 getRawY()
,然后将这些值与放置棋子的布局的左上角。知道了碎片的大小,我就可以确定选择了多少碎片。我意识到我可以在 MotionEvent
上使用 getX()
和 getY()
,但是这样会返回一个相对位置,从而确定哪些片段是选起来比较困难。 (我知道这并非不可能,但似乎不必要地复杂)。
编辑:这是我用来根据问题之一尝试获取容纳容器的大小的代码。 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
中的 ImageView 数组(cells[] 数组)。 Cells[0] 是左上角的 ImageView
,我选择了 cells[4],因为它位于中间的某个位置,并且绝对不应该具有 (0,0) 坐标。
上面显示的代码在日志中仍然给我全0,我真的不明白,因为各个拼图都正确显示。 (我尝试了 tableLayoutCorners 的 public int 和默认可见性,两者都给出了相同的结果。)
我不知道这是否重要,但是 ImageView
最初没有给出大小。当我给它一个要显示的图像时,ImageView
的大小在初始化期间由视图自动确定。即使日志代码是在给定图像并自动调整自身大小之后,这是否会导致它们的值为 0?为了潜在地解决这个问题,我添加了代码 tableLayout.requestLayout()
如上所示,但这没有帮助。
I'm trying to get the absolute screen pixel coordinates of the top left corner of a view. However, all methods I can find such as getLeft()
and getRight()
don't work as they all seem to be relative to the parent of the view, thus giving me 0
. What is the proper way to do this?
If it helps, this is for a 'put the picture back in order' game. I want the user to be able to draw a box to select multiple pieces. My assumption is that the easiest way to do that is to getRawX()
and getRawY()
from the MotionEvent
and then compare those values against the top left corner of the layout holding the pieces. Knowing the size of the pieces, I can then determine how many pieces have been selected. I realise I can use getX()
and getY()
on the MotionEvent
, but as that returns a relative position that makes determining which pieces were selected more difficult. (Not impossible, I know, but it seems unnecessarily complicated).
Edit: This is the code I used to try to get the size of the holding container, as per one of the questions. TableLayout
is the table which holds all the puzzle pieces.
TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
Log.d(LOG_TAG, "Values " + tableLayout.getTop() + tableLayout.getLeft());
Edit 2: Here is the code I've tried, following more of the suggested answers.
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]);
This code was added after all the initialisation is done. The image has been divided up into a array of ImageViews (the cells[] array) contained within a TableLayout
. Cells[0] is the top left ImageView
, and I picked cells[4] as it's somewhere in the middle and most definitely should not have coordinates of (0,0).
The code shown above still gives me all 0s in the logs, which I really don't understand because the various puzzle pieces are correctly displayed. (I tried public int for tableLayoutCorners and default visibility, both giving the same result.)
I don't know if this is significant, but the ImageView
s are originally not given a size. The size of the ImageView
s is determined during the initialisation automatically by the View when I give it an image to display. Could this contribute to their values being 0, even though that logging code is after they have been given an image and have automatically resized themselves? To potentially counter that, I added the code tableLayout.requestLayout()
as shown above, but that didn't help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
使用
View.getLocationOnScreen()
和/或getLocationInWindow ()
。Use
View.getLocationOnScreen()
and/orgetLocationInWindow()
.接受的答案实际上并没有告诉如何获取位置,所以这里有更多细节。您传入长度为 2 的
int
数组,并将值替换为视图的(左上角)的 (x, y) 坐标。注释
getLocationOnScreen
与getLocationInWindow
在大多数情况下应该给出相同的结果(请参阅此答案)。但是,如果您使用的是较小的窗口(例如对话框或自定义键盘),那么您将需要选择哪一个更适合您的需求。onCreate
中调用此方法,您将得到(0,0)
,因为视图尚未布局。您可以使用 ViewTreeObserver 来侦听布局何时完成,并且可以获得测量的坐标。 (请参阅此答案。)The accepted answer didn't actually tell how to get the location, so here is a little more detail. You pass in an
int
array of length 2 and the values are replaced with the view's (x, y) coordinates (of the top, left corner).Notes
getLocationOnScreen
withgetLocationInWindow
should give the same results in most cases (see this answer). However, if you are in a smaller window like a Dialog or custom keyboard, then use you will need to choose which one better suits your needs.(0,0)
if you call this method inonCreate
because the view has not been laid out yet. You can use aViewTreeObserver
to listen for when the layout is done and you can get the measured coordinates. (See this answer.)首先,您必须获取视图的 localVisible 矩形
例如:
希望这会有所帮助
First you have to get the localVisible rectangle of the view
For eg:
Hope this will help
使用全局布局侦听器对我来说一直很有效。它的优点是,如果布局发生更改,例如将某些内容设置为 View.GONE 或添加/删除子视图,则能够重新测量内容。
Using a global layout listener has always worked well for me. It has the advantage of being able to remeasure things if the layout is changed, e.g. if something is set to View.GONE or child views are added/removed.
第一种方式:
在Kotlin中,我们可以为视图创建一个简单的扩展:
并简单地获取坐标:
第二种方式:
第二种方式更简单:
只需通过
view.absX()
获取绝对 X 并通过view.absY()
获取绝对 YFirst Way:
In Kotlin we can create a simple extension for view:
And simply get coordinates:
Second Way:
The Second way is more simple :
and simply get absolute X by
view.absX()
and Y byview.absY()
根据 Romain Guy 的评论,我是如何解决这个问题的。希望它能帮助其他也遇到此问题的人。
我确实试图在视图显示在屏幕上之前获取视图的位置,但发生的情况一点也不明显。这些行是在初始化代码运行后放置的,所以我认为一切都准备好了。然而,这段代码仍然在 onCreate(); 中。通过尝试 Thread.sleep() 我发现布局实际上并没有最终确定,直到 onCreate() 一直到 onResume() 完成执行。事实上,代码试图在布局完成在屏幕上的定位之前运行。通过将代码添加到 OnClickListener(或其他监听器),可以获得正确的值,因为它只能在布局完成后触发。
下面的行被建议作为社区编辑:
请使用
onWindowfocuschanged(boolean hasFocus)
Following Romain Guy's comment, here's how I fixed it. Hopefully it'll help anyone else who also had this problem.
I was indeed trying to get the positions of the views before they had been laid out on the screen but it wasn't at all obvious that was happening. Those lines had been placed after the initilisation code ran, so I assumed everything was ready. However, this code was still in onCreate(); by experimenting with Thread.sleep() I discovered that the layout is not actually finalised until after onCreate() all the way to onResume() had finished executing. So indeed, the code was trying to run before the layout had finished being positioned on the screen. By adding the code to an OnClickListener (or some other Listener) the correct values were obtained because it could only be fired after the layout had finished.
The line below was suggested as a community edit:
please use
onWindowfocuschanged(boolean hasFocus)
您可以使用
getLocationOnScreen( )
或getLocationInWindow()
之后,
x
和y
应该是视图的左上角。如果您的根布局小于屏幕(例如在对话框中),则使用 getLocationInWindow 将相对于其容器,而不是整个屏幕。Java解决方案
为了确保视图有机会更新,请在使用
view.post
计算视图的新布局后运行位置请求:~~
Kotlin 解决方案
为了确保视图有机会更新,请在使用
view.post
计算视图的新布局后运行您的位置请求:我建议创建一个扩展函数来处理此问题:
如果您需要可靠性,还添加:
You can get a View's coordinates using
getLocationOnScreen()
orgetLocationInWindow()
Afterwards,
x
andy
should be the top-left corner of the view. If your root layout is smaller than the screen (like in a Dialog), usinggetLocationInWindow
will be relative to its container, not the entire screen.Java Solution
To ensure view has had a chance to update, run your location request after the View's new layout has been calculated by using
view.post
:~~
Kotlin Solution
To ensure view has had a chance to update, run your location request after the View's new layout has been calculated by using
view.post
:I recommend creating an extension function for handling this:
And if you require reliability, also add:
除了上述答案之外,对于您应该在何时何地调用
getLocationOnScreen
的问题?对于与
视图
相关的任何信息,只有在视图在屏幕上布局(创建)后才可用。因此,要获取位置,请将代码放入view.post(Runnable)
中,该代码在view
布局后调用,如下所示:Just in addition to the above answers, for the question where and when you should call
getLocationOnScreen
?For any information that is related to the
view
, will be available only after the view has been laid out (created) on the screen. So to get the location put your code insideview.post(Runnable)
which is called afterview
has been laid out, like this:我的 utils 函数用于获取视图位置,它将返回一个带有
x 值
和y 值
的Point
对象
My utils function for get view location, it will return a
Point
object withx value
andy value
Using
在屏幕上获取视图位置和尺寸
Get Both View Position and Dimension on screen
这是触摸屏幕时获取屏幕视图坐标的 Kotlin 方式。
确保同时处理向上和向下操作,否则可能会导致多次单击/触摸。
This is the Kotlin way of getting coordinates of screen view when you touch the screen.
Make sure you handle both Action UP and DOWN or it may cause multiple click/touch.