首页 文章

如何获取视图的绝对坐标

提问于
浏览
339

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

如果它有帮助,那就是'put the picture back in order'游戏 . 我希望用户能够绘制一个框来选择多个部分 . 我的假设是,最简单的方法是从 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 中包含的ImageViews(cells []数组)数组 . 单元格[0]是左上角 ImageView ,我选择了单元格[4],因为它位于中间的某个位置,绝对不应该有(0,0)的坐标 .

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

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

7 回答

  • 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);
    
  • -1

    按照Romain Guy的评论,这是我如何修复它 . 希望它能帮助那些也有这个问题的人 .

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


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

    请使用 onWindowfocuschanged(boolean hasFocus)

  • 16
  • 63

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

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

    Notes

    • getLocationInWindow替换getLocationOnScreen应该在大多数情况下给出相同的结果(参见this answer) . 但是,如果您使用的是较小的窗口,如Dialog或自定义键盘,那么您需要选择哪一个更适合您的需求 .

    • 如果在 onCreate 中调用此方法,则会得到 (0,0) ,因为视图尚未布局 . 你可以使用 ViewTreeObserver 来监听布局完成后你可以得到测量的坐标 . (见this answer . )

  • 72

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

    希望这会有所帮助

  • 39

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

    使用此代码查找确切的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);
    

    我添加/减去了一些值来调整我的视图 . Please do these lines only after whole view has been inflated.

相关问题