如何获取视图的绝对坐标

时间:2010-02-08 21:00:15

标签: android android-tablelayout

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

如果有帮助,这是为了“让图片重新整理”游戏。我希望用户能够绘制一个框来选择多个部分。我的假设是,最简单的方法是getRawX()中的getRawY()MotionEvent,然后将这些值与包含各个部分的布局的左上角进行比较。知道了件的大小,我就可以确定已经选择了多少件。我意识到我可以在getX()上使用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中包含的ImageViews(cells []数组)数组。单元格[0]是左上角ImageView,我选择了单元格[4],因为它位于中间的某个位置,绝对不应该有(0,0)的坐标。

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

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

11 个答案:

答案 0 :(得分:576)

答案 1 :(得分:89)

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

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

备注

  • 在大多数情况下,将getLocationOnScreen替换为getLocationInWindow应该会得到相同的结果(请参阅this answer)。但是,如果您在像Dialog或自定义键盘这样的较小窗口中,那么您需要选择哪一个更适合您的需求。
  • 如果您在(0,0)中调用此方法,则会获得onCreate,因为该视图尚未布局。你可以使用ViewTreeObserver来监听布局完成后你可以获得测量的坐标。 (见this answer。)

答案 2 :(得分:68)

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

希望这会有所帮助

答案 3 :(得分:44)

使用全局布局侦听器一直很适合我。它具有能够在布局改变时重新测量事物的优点,例如,如果某些内容设置为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);
 }

答案 4 :(得分:17)

按照Romain Guy的评论,这是我如何修复它。希望它能帮助其他任何有这个问题的人。

我确实试图在屏幕布局之前获得观点的位置,但事实并非如此。这些行已经在初始化代码运行后放置,所以我假设一切准备就绪。但是,此代码仍在onCreate()中;通过试验Thread.sleep()我发现布局实际上没有完成,直到onCreate()一直到onResume()完成执行。实际上,代码试图在布局完成定位在屏幕上之前运行。通过将代码添加到OnClickListener(或其他一些Listener),获得了正确的值,因为它只能在布局完成后触发。


以下行被建议为社区编辑:

请使用onWindowfocuschanged(boolean hasFocus)

答案 5 :(得分: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);

答案 6 :(得分:4)

除了上述答案外,还有关于您应在何时何地致电getLocationOnScreen的问题?

在与您想要获取的任何视图相关的任何信息中,只有在将视图布置在屏幕上之后,该信息才可用。您可以通过将依赖于视图创建的代码放入其中来轻松实现此目的:(view.post(Runnable))

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

答案 7 :(得分:1)

第一种方式:

科特林中,我们可以为视图创建一个简单的扩展名:

predict(Model, newdata=df)[1:4]
  245       246       247       248 
11.71199 272.55443 246.69057 220.82672 

只需获取坐标:

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,通过view.absX()获得Y

答案 8 :(得分:1)

您可以使用getLocationOnScreen()getLocationInWindow()

获取视图的坐标
int[] point = new int[2];
view.getLocationOnScreen(point); // or getLocationInWindow(point)
int x = point[0];
int y = point[1];

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

  

注意::如果值始终为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];
});

答案 9 :(得分: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]
                }

            }
        });
    }

答案 10 :(得分:-2)

使用此代码查找确切的X和Y坐标:

int[] array = new int[2];
ViewForWhichLocationIsToBeFound.getLocationOnScreen(array);
if (AppConstants.DEBUG)
    Log.d(AppConstants.TAG, "array  X = " + array[0] + ", Y = " + array[1]);
ViewWhichToBeMovedOnFoundLocation.setTranslationX(array[0] + 21);
ViewWhichToBeMovedOnFoundLocation.setTranslationY(array[1] - 165);

我添加/减去了一些值来调整我的视图。 请仅在整个视图曝光后执行这些行。