代码之家  ›  专栏  ›  技术社区  ›  Steve Haley

如何获取视图的绝对坐标

  •  351
  • Steve Haley  · 技术社区  · 16 年前

    我正在尝试获取视图左上角的绝对屏幕像素坐标。但是,我能找到的所有方法,如 getLeft() getRight() 不要工作,因为他们似乎都是相对于父母的观点,因此给了我 0 . 正确的方法是什么?

    如果有帮助的话,这是一个“把照片放回原样”的游戏。我希望用户能够绘制一个框来选择多个部分。我的假设是最简单的方法是 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]);
    

    此代码是在完成所有初始化后添加的。图像已被划分为包含在 表格布局 . 单元格[0]位于左上方 ImageView ,我选择了单元格[4],因为它在中间的某个位置,而且绝大多数情况下不应该有(0,0)的坐标。

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

    我不知道这是否重要,但是 图片框 S最初没有给定大小。尺寸 图片框 S是在初始化过程中由视图自动确定的,当我给它一个图像显示时。这是否会导致它们的值为0,即使日志代码是在它们被赋予图像并自动调整大小之后?为了反驳这一点,我添加了代码 tableLayout.requestLayout() 如上所示,但这没有帮助。

    8 回复  |  直到 7 年前
        2
  •  81
  •   Suragch Shmidt    8 年前

    接受的答案实际上并没有告诉我们如何获取位置,所以这里有一点更详细的内容。您传入一个长度为2的 int array,这些值将替换为视图的(x,y)坐标(顶部,左角)。

    int[]location=new int[2];
    myview.getlocation屏幕(位置);
    int x=位置[0];
    int y=位置[1];
    

    注意事项

    d值替换为视图的(x,y)坐标(位于左上角)。

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

    笔记

    • 替代getLocationOnScreen具有getLocationInWindow在大多数情况下都应给出相同的结果(参见this answer)但是,如果您在一个较小的窗口中,如对话框或自定义键盘,则使用时需要选择更适合您需要的窗口。
    • 你会得到(0,0)如果在onCreate因为这景色还没有布置好。你可以使用ViewTreeObserver倾听布局完成后,您可以获得测量的坐标。(参见this answer)
        3
  •  66
  •   Lavekush Agrawal rekire    8 年前

    首先,您必须获得视图的局部可见矩形

    例如:

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

    希望这会有帮助

        4
  •  43
  •   Siwei    8 年前

    使用全局布局侦听器对我来说总是很有效的。它的优点是,如果布局发生更改,可以重新测量对象,例如,如果某个对象设置为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);
     }
    
        5
  •  16
  •   Adi Inbar    12 年前

    在罗曼·盖伊的评论之后,以下是我如何修复的。希望它能帮助其他有这个问题的人。

    我确实是想在屏幕上显示之前得到视图的位置,但这并不明显。这些行是在初始化代码运行之后放置的,所以我假设一切都准备就绪。但是,这个代码仍然在oncreate()中;通过对thread.sleep()的实验,我发现在oncreate()执行完之后,布局才真正完成。因此,实际上,代码是在布局在屏幕上完成定位之前尝试运行的。通过将代码添加到onclickListener(或其他一些侦听器)中,可以获得正确的值,因为只有在布局完成后才能激发该值。


    下面的行建议作为社区编辑:

    请使用 onWindowfocuschanged(boolean hasFocus)

        6
  •  5
  •   Linh    8 年前

    我的utils函数用于获取视图位置,它将返回 Point 对象与 x value y 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);
    
        7
  •  0
  •   Amir Hossein Ghasemi    7 年前

    第一种方式:

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

    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 view.absY()

        8
  •  -2
  •   Tarun Deep Attri    10 年前

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

    我添加/减去了一些值来调整我的视图。 请在整个视野被放大后再画这些线。