在我看来,Android的坐标系存在问题。当我有一个普通的视图(没有请求FEATURE_NO_TITLE
)时,我会检索int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
。这为状态栏提供了76px
:38px
,标题栏为38px
。
但是,如果我请求FEATURE_NO_TITLE
然后重复此过程,getTop()
会返回0px
,尽管状态栏仍然可见! / p>
这种差异不应该有所不同,因为我们通常不关心内容视图的开始位置。但是, 对我来说很重要,因为我将视图放在装饰视图上 - 它覆盖了整个可见窗口。
我知道这不是标题栏和设备密度的诀窍,因为如果我请求自定义标题栏并将其设为0
高度,则getTop()
会返回38px
}。
解决方案/解决方法是在请求FEATURE_NO_TITLE
时手动添加38个像素。我的问题是:这是一个Android错误吗?或者是否有一些我不了解布局如何工作会使这种行为变得可理解?
提前致谢!
这是一个重现问题的最小程序。运行两次,取消注释指示的行。我正在编译Android SDK 7,并使用Android 2.3.4在Samsung Galaxy S上运行。
main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layoutParent"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="@+id/someId"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</LinearLayout>
</RelativeLayout>
TestStatusBarActivity.java
package com.test.teststatusbar;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.Window;
import android.widget.RelativeLayout;
public class TestStatusBarActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Uncomment the following line to see the alternate behavior
//requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
RelativeLayout layoutParent = (RelativeLayout) findViewById(R.id.layoutParent);
View something = findViewById(R.id.someId);
something.setBackgroundColor(Color.CYAN);
ViewTreeObserver vto = layoutParent.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// decor window top
Rect rectgle = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight = rectgle.top;
// "content view" top
int contentViewTop = window.findViewById(
Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight = contentViewTop - StatusBarHeight;
Log.i("STATUSBARTEST", "StatusBar Height = " + StatusBarHeight
+ " , TitleBar Height = " + TitleBarHeight
+ ", Content top = " + contentViewTop);
}
});
}
}
答案 0 :(得分:4)
这是一个Android错误吗?
没有。系统只是构建视图层次略有不同,在两种情况下都要避免不必要的深度(出于性能原因,更多(嵌套)布局元素意味着更多的开销)。
以下是标题栏的层次结构:
注意:我的像素值与您的像素值略有不同,因为我在较小的模拟器上运行了您的示例。对于这种情况,这应该无关紧要。
包含标题栏和内容布局的基本LinearLayout填充整个显示。它在这里也有25px的填充,因为状态栏覆盖了正常的UI层次结构。因此必须通过填充保留一些空间。
然后将标题栏作为LinearLayout的第一个元素,也是25 px高度。这意味着findViewById(Window.ID_ANDROID_CONTENT).getTop();
总共返回50,因为contentview FrameLayout距其顶部的LinearLayout (再次为25个填充+25个标题)的顶部为50像素。这是正确的。
那么,标题栏被删除后会发生什么?
系统完全剥离外部LinearLayout,这意味着内容视图现在填满整个屏幕。 findViewById(Window.ID_ANDROID_CONTENT).getTop();
应该在这里返回0,它实际上是什么。这没错。但是必须再次为状态栏预留空间。系统在此处将填充分配给contentview。
如何修复
我认为解决方案非常简单:您必须包含contentview的填充以获得准确的结果。例如。改变
int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
到
View contentView = window.findViewById(Window.ID_ANDROID_CONTENT);
int contentViewTop = contentView.getTop() + contentView.getPaddingTop();
这会为我打印出正确的结果。
答案 1 :(得分:0)
这取决于我认为您使用的Android版本。我在三星Galaxy Y(2.3.6)和HTC Desire HD(2.3.5)上尝试了你的代码,它就像你描述的那样发生了。但是,使用HTC ONE V(4.0.3),结果如预期正确。没有标题的视图顶部返回0 px。因此,您不应该依赖此输出,因为它可能无法在每部手机中正确显示。