【问题标题】:Android: Why is there a discrepancy in ContentView.getTop() depending on FEATURE_NO_TITLE?Android:为什么 ContentView.getTop() 根据 FEATURE_NO_TITLE 存在差异?
【发布时间】:2012-05-30 20:23:04
【问题描述】:

在我看来,Android 的坐标系有问题。当我有一个正常的视图(没有请求FEATURE_NO_TITLE)时,我会检索int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();。这给了我76px38px 用于状态栏,38px 用于标题栏。

但是,如果我请求FEATURE_NO_TITLE 然后重复该过程,getTop() 将返回0px,尽管状态栏仍然可见!

这种差异应该不会产生影响,因为我们通常不关心内容视图从哪里开始。但是,它确实对我很重要,因为我将视图放置在装饰视图上——它覆盖了整个可见窗口。

我知道这不是标题栏和设备密度的技巧,因为如果我请求自定义标题栏,并给它0 高度,那么getTop() 返回38px

解决方案/解决方法是在请求 FEATURE_NO_TITLE 时手动添加 38 个像素。我的问题是:这是一个 Android 错误吗? 或者有什么我不理解的布局如何使这种行为可以理解?

提前致谢!

这是一个重现问题的最小程序。运行它两次,然后取消注释指示的行。我正在针对 Android SDK 7 进行编译,并在装有 Android 2.3.4 的三星 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);
            }
        });

    }
}

参考文献

【问题讨论】:

    标签: android layout statusbar titlebar custom-titlebar


    【解决方案1】:

    这是一个 Android 错误吗?

    没有。系统只是在两种情况下构建的视图层次结构略有不同,确实避免了不必要的深度(出于性能原因,更多(嵌套)布局元素意味着更多开销)

    下面是带有标题栏的层次结构:

    注意:我的像素值与您的略有不同,因为我在较小的模拟器上运行了您的示例。对于这种情况,这应该无关紧要。

    full size

    包含标题栏和内容布局的基本 LinearLayout 会填满整个显示屏。它在这里也有一个 25px 的填充,因为状态栏覆盖了正常的 UI 层次结构。所以必须通过填充保留一些空间。

    然后将标题栏作为 LinearLayout 的第一个元素,高度也为 25 像素。这意味着findViewById(Window.ID_ANDROID_CONTENT).getTop(); 总共返回 50,因为 contentview FrameLayout 距离其父 LinearLayout 顶部 50 像素(同样是 25 padding + 25 title)。哪个是正确的。

    那么,当标题栏被移除时会发生什么?

    full size

    系统完全剥离了外部的 LinearLayout,这意味着 contentview 现在填满了整个屏幕。 findViewById(Window.ID_ANDROID_CONTENT).getTop(); 应该在这里返回 0,它实际上是做什么的。这没有错。但是必须再次为状态栏保留空间。系统在此处将该填充分配给内容视图。

    如何解决

    我认为解决方案非常简单:您必须包含 contentview 的填充才能获得准确的结果。例如。改变

    int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
    

    View contentView = window.findViewById(Window.ID_ANDROID_CONTENT);
    int contentViewTop = contentView.getTop() + contentView.getPaddingTop();
    

    这将为我打印正确的结果。

    【讨论】:

    • 好吧,我自己学到了一些东西,帮助了你,我喜欢这里的问题,这些问题不是通常的懒惰“我想构建 thisthatbla,快点给我代码”。所以:很高兴我能提供帮助,也感谢您提出精心设计的问题。
    【解决方案2】:

    这取决于我认为您使用的 android 版本。我已经在三星 Galaxy Y (2.3.6) 和 HTC Desire HD (2.3.5) 上尝试过你的代码,它就像你描述的那样发生了。但是,使用 HTC ONE V (4.0.3) 时,结果与预期的一样正确。没有标题的视图顶部返回 0 像素。所以你不应该依赖这个输出,因为它可能不会在每个电话中都正确。

    【讨论】:

    • 您是否尝试像上面描述的@alextsc 那样使用contentView.getTop() + contentView.getPaddingTop();?那是一致的吗?因为这就是我正在使用的,而且在我尝试过的每台设备上看起来都很完美。
    猜你喜欢
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-07
    • 2016-03-23
    • 1970-01-01
    • 2012-10-27
    • 2021-02-05
    相关资源
    最近更新 更多