35

我正在将代码库从本机 Holo(Theme.Holo等)移植到appcompat-v7(等Theme.AppCompat)。如果您不想阅读详细信息,最后一部分包含tl;dr 。


问题

一切正常,但我在复制一种使用旧 ActionBar 很容易实现的行为时遇到了问题。我有一个视频播放器,在横向上我希望它的行为类似于 YouTube:隐藏(动画)播放器控件、应用栏和状态栏。在用户交互时,UI 控件应离开此“熄灯”模式并返回正常状态。如果用户在 X 秒内没有触摸屏幕,计时器将返回熄灯模式。与 ActionBar 一起工作的相同代码对Toolbar.

所以,我使用的是:

  • 不透明的状态栏
  • setSystemUiVisibility()使用以下组合之一:
    • 默认:View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    • 熄灯:View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  • minSdkVersion是 16
  • 显示和隐藏我简单调用的show()ActionBarhide()
  • 为了在应用栏上实现相同的行为,我子类化Toolbar并添加了一个show()和一个hide()执行相同操作的方法(首先简单地使用setVisibility(),然后使用动画 - 获得相同的结果)

这样LAYOUT_STABLE做是为了让 appbar 最终位于状态栏的后面,当然(因为它暗示了一个fitSystemWindows. 由于 appbar 是视图层次结构中的普通视图,并且不像 ActionBar 那样在装饰中,所以它受该标志的影响. 这就是我在屏幕上看到的:

状态栏后面的应用栏

无法立即清楚工具栏的边界是什么,因为应用程序栏在黑暗中是黑暗的,但您可以看到标题被剪切并且“未对齐”。这是因为工具栏的大小正确但位于状态栏后面。我的主要问题是当时没有公共 API 来获取状态栏高度、矩形或其他任何东西来垂直移动我的应用栏以显示在状态栏下方。

测试主要在 N5 上的 LPX13D(撰写本文时最新的 Lollipop 公共版本)上进行,但在 Android 4.4 上也可以看到同样的情况。


骇人听闻的解决方案

也就是说,经过相当长的一段时间和一些失败的尝试以一种不太老套的方式工作(包括相当绝望的尝试自己将其放入装饰中),我采用了这种令人讨厌的方式让它工作:

  1. onResume
    一个。setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE)即使我通常不会打电话(风景)
    b. 注册一个OnPreDrawListener

  2. OnPreDrawListener
    _ View root = getRootView().findViewById(R.id.my_root)
    使用b获取根视图。获取根视图高度:(int rootTop = getAbsoluteViewTop(root)见下文)
    c. 使用该顶部(将其作为状态栏高度)作为 appbar
    d 的 paddingTop。设置我通常使用的 SystemUiVisibility (LAYOUT_STABLE等)
    e。抑制绘图通道

  3. 在下一个绘图过程中,取消注册OnPreDrawListener

这是getAbsoluteViewTop()方法:

private int getAbsoluteViewTop(View view) {
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    return location[LOCATION_Y];
}

tl;博士和问题

tl; drToolbar :除非采用 hacky hack,否则无法使用a 进行适当的“熄灯”模式。

问题:是否有官方和干净的方式来实现这种熄灯模式Toolbar
我在文档中找不到任何内容。状态栏无法访问(并且您可以在 SO 上找到其大小的所有方法都已损坏,仅供参考)。但也许我错过了一些东西。我很想摆脱这个黑客。

4

2 回答 2

1

fitssystemwindows当您希望视图层次结构的某些元素全屏显示并且某些元素位于状态栏或操作栏下方时,我也发现非常不可靠。但我从未见过状态栏后面的操作栏。工具栏是否设置为活动操作栏?你在用Window.FEATURE_ACTION_BAR_OVERLAY吗?无论如何,如果您只需要为paddingTopin获取多个像素onResume(),那么执行以下操作而不是使用OnPreDrawListeners.

class MyVideoActivity extends Activity {
    Toolbar bar;

    //...

    @Override protected void onResume() {
        super.onResume();
        bar.setPaddingTop(getStatusBarHeight());
    }

    int getStatusBarHeight() {
        int result = 0;
        Resources res = getResources();
        int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = res.getDimensionPixelSize(resourceId);
        }
        return result;
    }
}
于 2014-11-11T10:50:34.153 回答
1

不确定这是否会有所帮助,但您是否看过使用

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

在您的视频活动的 onCreate 方法中?这可能是一个很好的起点。这基本上隐藏了状态栏并使我的视频全屏显示。

这是我也使用的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:background="@color/black">

        <VideoView
            android:id="@id/videoSurface"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:layout_centerInParent="true"
            android:layout_alignParentTop="true"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentRight="true"
            android:layout_gravity="center"
            />

</RelativeLayout>

我知道有些参数是多余的,但最终它给了我想要的效果。这对您来说可能是一个很好的起点?

于 2015-04-17T15:16:48.087 回答