我试图获得一个视图的左上角的绝对屏幕像素坐标。然而,我能找到的所有方法,如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()代码,但这并没有帮助。


当前回答

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

希望这能有所帮助

其他回答

binding.ivStory.setOnTouchListener(object : View.OnTouchListener{
        override fun onTouch(p0: View?, event: MotionEvent?): Boolean {
            val x = event?.x
            vak y = event?.y

            when (event!!.action) {
                MotionEvent.ACTION_UP ->

                if (x != null) {
                   //Do your stuff                    }

                MotionEvent.ACTION_DOWN  -> {

                }
            }
            return true
        }

    })

当你触摸屏幕时,这是Kotlin获得屏幕视图坐标的方法。 确保你同时处理动作向上和向下,否则可能会导致多次点击/触摸。

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

希望这能有所帮助

根据Romain Guy的评论,以下是我如何修复它。希望它能帮助其他有这个问题的人。

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.


下面这句话是建议社区编辑的:

请使用onWindowfocuschanged(boolean hasFocus)

使用View.getLocationOnScreen()和/或getLocationInWindow()。

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