从getLocationOnScreen/getLocationInWindow获取的坐标不正确。

63

调用 getLocationOnScreen()getLocationInWindow() 方法,它们都会给我一个关于top/Y坐标的结果,但是它距离实际位置(状态栏/通知栏高度)偏低了大约30像素。而left/X坐标则完全正确。

正如我上面提到的,我认为差异是由于状态栏/通知栏造成的...但我可能错了。如果我能确定通知栏的大小,我认为我可以解决这个问题,但是我现在遇到了麻烦。

任何帮助将不胜感激。

7个回答

86

我最终通过以下方式确定状态/通知栏的高度来解决了这个问题:

View globalView = ...; // the main view of my activity/application

DisplayMetrics dm = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(dm);
int topOffset = dm.heightPixels - globalView.getMeasuredHeight();

View tempView = ...; // the view you'd like to locate
int[] loc = new int[2]; 
tempView.getLocationOnScreen(loc);

final int y = loc[1] - topOffset;

这在正常配置下是有效的,但如果活动在打开SoftInput/键盘时调整'globalView'高度,则键盘高度也会计入'topOffset',这将导致'y'的值错误。 - Thamme Gowda
8
int[] locInWindow = new int[2]; //创建一个长度为2的整型数组locInWindow globalView.getLocationInWindow(locInWindow); //获取globalView在窗口中的坐标并存储在locInWindow数组中 topOffset = locInWindow[1]; //通过获取 globalView 的Y坐标来计算topOffset - Thamme Gowda
@ThammeGowda,您能否详细解释一下当键盘打开时我如何获取顶部偏移量? - Hussien Fahmy

10

这是我获取状态栏高度、并调整偏移量的方法:

final int[] location = new int[2];
anchor.getLocationInWindow(location); // Includes offset from status bar, *dumb*
Rect anchorRect = new Rect(location[0], location[1],
        location[0] + anchor.getWidth(), location[1] + anchor.getHeight());

anchor.getRootView().findViewById(android.R.id.content).getLocationInWindow(location);
int windowTopOffset = location[1];
anchorRect.offset(0, -windowTopOffset);

为什么窗口中的位置包括状态栏偏移量这一点很愚蠢?你要求的是在窗口中的位置,那你还能期望其他什么呢? - Alex Lockwood
2
人们会认为窗口在状态栏下方,因此偏移量不包括状态栏的高度。 - satur9nine
你可能把窗口和屏幕搞混了。 - Martin Marconcini
windowTopOffset 包括操作栏的高度,而不仅仅是状态栏的高度。 - brillenheini
这在所有设备上都完美运行。与上面的答案相比较。 - Vishal Bhandare

4
我遇到了同样的问题,请尝试使用。
offset = myView.GetOffsetY();

并通过该值调整您的Y坐标,例如:

coordY -= offset;

提供“-method”的类:
class MyView extends View {

  public int GetOffsetY() {
    int mOffset[] = new int[2];
    getLocationOnScreen( mOffset );
    return mOffset[1]; 
  }

}

我没有看到“getOffsetY()”。那是哪个类的方法? - nimph
抱歉,我未能发布该方法:在 MyView 类中:public int GetOffsetY() { int mOffset[] = new int[2]; getLocationOnScreen( mOffset ); return mOffset[1]; } - user330844

4

这个答案并不包括如何获取状态栏的高度,但是它解释了getLocationOnScreen()getLocationInWindow()返回相同值的行为。

对于普通活动(而不是对话框),您应该期望这两种方法返回相同的值。窗口在状态栏下面布局(按z顺序而不是y坐标),因此这些方法不能用于确定状态栏的高度。

https://dev59.com/FmMm5IYBdhLWcg3wX-AW#20154562


在对话框视图中,如果未将窗口全屏设置为true,则可以正常工作,但如果设置如下所示:<item name="android:windowFullscreen">true</item>则该值不正确,因此需要减去“topOffset”。 - iXcoder

1

正如 @ThammeGowda 所说,当键盘显示时,正确答案将给出错误的位置,但您仍然需要计算操作栏的顶部偏移量,因此直接获取操作栏的大小即可

fun View.getPosition(): Point {
    val tv = TypedValue()
    if (context.theme.resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
        val actionBarHeight =
            TypedValue.complexToDimensionPixelSize(tv.data, resources.displayMetrics)

        val loc = IntArray(2).apply { getLocationInWindow(this) }

        val newY = loc[1] - actionBarHeight - (measuredHeight / 2) // to get the position in the middle of the view

        return Point(loc[0], newY)
    }
    return Point(0,0)
}

enter image description here


0
 void setOffset(){
  int[] point1=new int[2];
  view1.getLocationInWindow(point1);
  
  int[] point2=new int[2];
  view2.getLocationInWindow(point2);

  int leftOffset=point2[0]-point1[0];
  int topOffset=point2[1]-point1[1];  
  // no need to call this function more than once
  // set the offset values in global variables 
  // remenber do't call it in OnCreate method
  // this helps to mesure all type of screen size
}

void setLocationOfView(){
  // now do your animation or any view to move
 int[] point =new int[2];
 sourceView.getLocationInWindow(point);
 view.setX(point[0]-leftOffset);
 view.setY(point[1]-topOffset);
 //wow you did it i am glad to help you and sorry for being late
}

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0

解决方案:

  1. 在顶部放置一个不可见的png ImageView
android:layout_marginTop="0dp"
获取不可见PNG文件在屏幕上的位置。这将是您的y坐标错误的偏移量。
int[] location = new int[2];

invisiblepng.getLocationOnScreen(location);

int sourceY = location[1];

SharedPreferences.Editor editor = sp.edit();

editor.putString("compensateybug", Integer.toString(sourceY));

editor.apply();
 and
public static Point getLocationOnScreen(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
return new Point(location[0], location[1]);
}
检索“状态/通知栏”的Y坐标值。
String compensateybug = sp.getString("compensateybug", "0");

int yourycoordinate = parseInt(compensateybug);

我已经附上了一个用于下载的不可见的PNG图像文件

https://drive.google.com/file/d/1zxhP1r6ISvKG8Ig8iItDY2x6k5RVo4Nu/view?usp=sharing


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接