我试图获得一个视图的左上角的绝对屏幕像素坐标。然而,我能找到的所有方法,如getLeft()和getRight()都不工作,因为它们似乎都是相对于视图的父视图,因此给我0。正确的做法是什么?

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).

编辑:这是我用来尝试得到持有容器的大小的代码,每一个问题。tableelayout是包含所有拼图碎片的表格。

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

这段代码是在所有初始化完成后添加的。图像被划分为一个包含在tableelayout中的ImageViews数组(cells[]数组)。单元格[0]是ImageView的左上角,我选择单元格[4]是因为它在中间的某个地方而且它的坐标肯定不应该是(0,0)

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

我不知道这是否重要,但ImageViews最初没有给定大小。ImageViews的大小是在初始化过程中由视图自动决定的,当我给它一个图像来显示。这是否会导致它们的值为0,即使日志代码是在给它们一个图像并自动调整自己的大小之后?为了潜在地解决这个问题,我添加了如上所示的tableLayout.requestLayout()代码,但这并没有帮助。


当前回答

第一个方法:

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

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]
}

通过view.absX()和view.absY()获得绝对X

其他回答

使用全局布局监听器对我来说一直都很有效。它的优点是,如果布局发生改变,例如,如果某些东西被设置为视图,则可以重新测量。添加/删除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);
 }

第一个方法:

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

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]
}

通过view.absX()和view.absY()获得绝对X

你可以使用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];

注意:如果value总是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];
});

~~

芬兰湾的科特林解决方案

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

注意:如果value总是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)
    }
}

在屏幕上获得视图位置和尺寸

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]
                }

            }
        });
    }

首先,你必须获得视图的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));

希望这能有所帮助