半透明/透明状态栏 + CoordinatorLayout + Toolbar + Fragment

Posted

技术标签:

【中文标题】半透明/透明状态栏 + CoordinatorLayout + Toolbar + Fragment【英文标题】:Translucent/Transparent status bar + CoordinatorLayout + Toolbar + Fragment 【发布时间】:2016-04-18 03:08:50 【问题描述】:

我有以下设置:

我正在使用 AppCompat MainActivity,包含一个片段和一个工具栏,向下滚动时隐藏 FragmentRecyclerView 所有应该适合屏幕的视图在 xml 布局中都有相应的android:fitsSystemWindows="true"

问题是,在这种情况下,我无法让状态栏透明。我所做的是:

    创建活动并调用 setContent

    然后我尝试调整活动以编程方式获得半透明工具栏,如下所示:

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void themeNavAndStatusBar(Activity activity)
    
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
            return;
    
        Window w = activity.getWindow();
        w.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        w.setFlags(
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        w.setFlags(
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        w.setNavigationBarColor(activity.getResources().getColor(android.R.color.transparent));
    
        w.setStatusBarColor(activity.getResources().getColor(android.R.color.transparent));
    
    

    将活动中的占位符(@+id/frame_container)替换为片段

在这种情况下,状态栏是纯色的,并且视图不会在其下方绘制...为什么?

我想要什么

我想要一个工具栏,它可以滚动屏幕并完全隐藏,而该工具栏下方的内容应该适合屏幕并绘制在透明导航栏后面。

布局

这是我的主要活动:

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/clMain"
    android:fitsSystemWindows="true"
    android:background="?attr/main_background_color"
    android:layout_
    android:layout_>

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBarLayout"
        android:fitsSystemWindows="true"
        android:background="@null"
        app:elevation="0dp"
        app:contentInsetLeft="0dp"
        app:contentInsetStart="0dp"
        android:layout_
        android:layout_>

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_
            android:layout_
            android:background="?attr/colorPrimary"
            android:elevation="4dp"
            android:theme="?actionBarThemeStyle"
            app:popupTheme="?actionBarPopupThemeStyle"
            app:layout_scrollFlags="scroll|enterAlways">

            <LinearLayout
                android:orientation="vertical"
                android:layout_
                android:layout_>

                <LinearLayout
                    android:orientation="horizontal"
                    android:layout_
                    android:layout_>

                    <ImageView
                        android:id="@+id/ivToolbarDataSource"
                        android:layout_gravity="center_vertical"
                        android:layout_marginRight="2dp"
                        android:layout_
                        android:layout_ />

                    <TextView
                        android:id="@+id/tvToolbarTitle"
                        style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
                        android:theme="?actionBarThemeStyle"
                        android:layout_gravity="center_vertical"
                        android:layout_
                        android:layout_ />

                </LinearLayout>

                <TextView
                    android:id="@+id/tvToolbarSubTitle"
                    style="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle"
                    android:theme="?actionBarThemeStyle"
                    android:layout_
                    android:layout_ />

            </LinearLayout>



        </android.support.v7.widget.Toolbar>

        <!-- BUG: http://***.com/questions/30541409/coordinatorlayoutappbarlayout-does-not-draw-toolbar-properly -->
        <View
            android:layout_
            android:layout_/>

    </android.support.design.widget.AppBarLayout>

    <FrameLayout
        android:id="@+id/frame_container"
        android:fitsSystemWindows="true"
        android:layout_
        android:layout_
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_
        android:layout_
        android:layout_gravity="bottom|right"
        android:layout_margin="32dp"
        android:src="@drawable/ic_local_offer_white_24dp"
        app:backgroundTint="?attr/colorPrimary"
        app:borderWidth="0dp"
        app:fabSize="normal"
        app:rippleColor="?attr/colorPrimaryDark"
        app:layout_anchorGravity="bottom|right|end"
        app:layout_behavior="com.test.classes.ScrollAwareFABBehavior"/>

</android.support.design.widget.CoordinatorLayout>

这是我的片段,将放置在主要活动中:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:fitsSystemWindows="true"
    android:layout_
    android:layout_>

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/srlImages"
        android:fitsSystemWindows="true"
        android:layout_
        android:layout_>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rvImages"
            android:fitsSystemWindows="true"
            android:layout_
            android:layout_ />

    </android.support.v4.widget.SwipeRefreshLayout>

    <TextView
        android:id="@+id/tvEmpty"
        android:gravity="center"
        android:layout_centerInParent="true"
        android:layout_
        android:layout_ />

</RelativeLayout>

编辑 - 屏幕截图

我使用浅色/深色基础主题和手动主题(因为用户可以选择任何颜色作为主要/强调色),所以不要介意工具栏是白色的(它是默认的主题背景颜色和主要颜色)颜色)。我还添加了一个黑色边框,以便您看到活动结束的位置...

第一个屏幕截图:显示工具栏,没有滚动 第二个屏幕截图:我刚刚开始滚动 => 工具栏现在应该滚开 第三个屏幕截图:主要内容现在应该在导航栏下方滚动...

最后,我当然会将工具栏和导航栏设置为半透明,以获得更好的视觉效果...

【问题讨论】:

你能发一些图片吗?您可能应该将 fitSystemWindows 设置为 false 到 CoordinatorLayout (至少)。 我添加了截图来显示问题... 在 CoordinatorLayout 和 frame_container 中将 fitSystemWindows 设置为 false。 【参考方案1】:

tl;dr 至少将android:fitsSystemWindows="false" 设置为根CoordinatorLayout 和内部片段容器@frame_container

这可能不是最终解决方案(即可能还有其他 fitsSystemWindows 需要更改)所以如果您有任何问题,请告诉我。

为什么

说到状态栏,我想到fitsSystemWindows是这样的:

fitsSystemWindows="false" : 正常绘制视图,状态栏下,因为你设置了窗口标志。 fitsSystemWindows="true" :正常绘制视图,状态栏,因为您设置了窗口标志,但是添加了顶部填充,以便在状态栏下方绘制内容并且它们不重叠。

其实在我看来,你看到的白色并不是状态栏颜色,而是你的CoordinatorLayout背景。这是由于协调器上的fitsSystemWindows="true":它将背景绘制到整个窗口,但在内容中添加了顶部填充,因此状态栏不会覆盖内部视图。

这不是你想要的。您的内部内容必须被状态栏覆盖,因此您必须将 fitsSystemWindows="false" 设置为协调器(因此它不会应用顶部填充),并且可能设置为内容本身。

一旦你了解了它的工作原理,就很容易调试并达到你想要的效果其实不然。多年过去了,但我仍然花费数小时试图找出正确的 fitSystemWindows 组合,因为大多数视图(至少在支持库中)以大多数不直观的方式覆盖了我上面提到的默认行为。有关如何使用它的小指南,请参阅 this post。

【讨论】:

android:fitsSystemWindows="false" 的问题是工具栏现在也在状态栏后面。 "其实在我看来,你看到的白色并不是状态栏颜色,而是你的CoordinatorLayout背景。"非常感谢!! @HammadNasir 我认为更好的方法是设置android:fitsSystemWindows="true"coordinateLayout 设置app:statusBarBackground="@android:color/transparent" 也请看这个答案:***.com/a/47906087/2201814【参考方案2】:

编辑你的styles.xml (v21),添加如下样式

 <style name="AppTheme.Home" parent="AppTheme.Base">
    <!-- Customize your theme here. -->
    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:windowTranslucentNavigation">true</item>

</style>

您可以根据自己的喜好更改父主题,但现在在您的 AndroidManifest.xml 文件中为特定活动声明此主题,如下所示:

 <activity
        android:theme="@style/AppTheme.Home"
        android:name=".HomeActivity"
        android:launchMode="singleTop"
        android:screenOrientation="portrait" />

这将使您的内容在透明操作栏下可见。

现在使用以下命令正确对齐 StatusBar 下方的工具栏,在 oncreate 中调用它:

 toolbar.setPadding(0, getStatusBarHeight(), 0, 0);

使用以下方法获取状态栏高度:

public int getStatusBarHeight() 
    int result = 0;
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) 
        result = getResources().getDimensionPixelSize(resourceId);
    
    return result;

从您的协调器布局标签中删除以下内容:

android:fitsSystemWindows="true"

现在要折叠或隐藏工具栏,您可以参考this tutorial

确保您使用的是以下版本的设计支持库,因为它没有错误:

compile 'com.android.support:design:23.1.0'

【讨论】:

谢谢,您的解决方案有效。我重写了在状态栏下方对齐工具栏,不仅添加了填充,还添加了工具栏的高度。我的意思是toolbar.getLayoutParams().height += getStatusBarHeight(); 另外,AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) toolbar.getLayoutParams(); lp.topMargin += getStatusBarHeight();【参考方案3】:

在阅读了您对问题的描述后,我认为 Google 相册 的样式符合您的要求。

好的,这里只是针对您的问题的一些提示。经过我的测试,它可以工作了。

如果你想在状态栏后面显示内容,你需要添加&lt;item name="android:windowTranslucentStatus"&gt;true&lt;/item&gt;到你的 Android版本级别大于19时的样式(即KitKat) 如果你想在导航栏后面显示内容,你需要添加 &lt;item name="android:windowTranslucentNavigation"&gt;true&lt;/item&gt; 进入你的 Android版本级别大于19时的样式(即KitKat) 如果你想在内容向上滚动时平滑隐藏Toolbar 并在内容向下滚动时平滑地显示Toolbar,您 需要将app:layout_collapseMode="parallax" 添加到您的 Toolbar的属性基于你当前的代码。当然,你 需要坐标ToolbarCollapsingToolbarLayout CoordinatorLayoutAppBarLayout

【讨论】:

你没有在描述性文本中混淆状态和导航栏吗? 我搞错了什么? @SilentKnight,“如果你想在状态栏后面显示内容”和“android:windowTranslucentNavigation”。也许你混合了描述。不过谢谢,它有帮助。【参考方案4】:

正如一些用户所说,通过设置android:fitsSystemWindows="false",布局在statusbar下方重叠

我通过设置android:fitsSystemWindows="true"CoordinatorLayout标签设置app:statusBarBackground="@android:color/transparent"解决了这个问题。

【讨论】:

哦,谢谢老兄!我花了半天的时间,找出为什么我的片段增加了状态栏额外的高度。 惊人的发现 ;)【参考方案5】:

对我来说,原因不是它本身不起作用,而是我使用了 Mike Penz 的材质抽屉库,而这个库确实使用了工具栏后面的全屏 + 偏移 + 自定义背景,所以我必须解决这个问题尊重那个特殊的设置......

不过,我会将积分奖励给我认为最丰富的答案...

【讨论】:

v5.0.0 将停止执行偏移等。它将使用平台默认值并依赖于fitsSystemWindows 标志。还有 CollapsingToolbar 例子github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/…【参考方案6】:

我遇到了同样的问题,我的解决方案是将 android:fitsSystemWindows="true" 添加到 DrawerLayout

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_
    android:layout_
    android:fitsSystemWindows="true"> 

....

</android.support.v4.widget.DrawerLayout>

【讨论】:

抱歉,这对我没有帮助。请参阅上面的答案,它们可能会有所帮助。【参考方案7】:

我有相关问题取决于 android:fitsSystemWindows 设置。 一旦错误: 小吃被绘制在导航栏下 一旦为真: 状态栏没有透明背景

解决方案真的很简单... 只需添加 android:layout_marginBottom="48dp"。像这样的 CoordinatorLayout:

just to add <android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:map="http://schemas.android.com/apk/res-auto"
tools:context=".MapsActivity"
android:id="@+id/coordinatorLayout"
android:layout_
android:layout_

android:fitsSystemWindows="false"
android:layout_marginBottom="48dp">

理论上导航栏应该有固定大小“48dp”,但在未来的版本中它可能会改变(比如状态栏在棉花糖中变细了 1dp),所以我不会依赖固定大小。 最好另外获取它并在运行时应用。

如果您像我一样使用 Google 地图,您可能想知道 ActionBar/Toolbar 的大小以及运行时的导航栏:

在 onCreate 中使用此代码:

            final TypedArray styledAttributes = MapsActivity.this.getTheme().obtainStyledAttributes(
                new int[]android.R.attr.actionBarSize);
        mToolbarHeight = (int) styledAttributes.getDimension(0, 0);
        styledAttributes.recycle();
        // translucent bars code. Will not fire below Lollipop
        // Ask NavigationBar Height
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.coordinatorLayout),
                new OnApplyWindowInsetsListener()  // setContentView() must be fired already
                    @Override
                    public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) 
                        statusBar = insets.getSystemWindowInsetTop(); // You may also need this value
                        mNavBarHeight = insets.getSystemWindowInsetBottom();
                        if (mMap != null)
                            mMap.setPadding(0, mToolbarHeight, 0, mNavBarHeight);
                        // else will be set in onMapReady()
                        SharedPreferences.Editor editor = mSharedPref.edit();
                        editor
                                .putInt(NAVBAR_HEIGHT_KEY, mNavBarHeight)
                                .commit(); // Save the results in flash memory and run the code just once on app first run instead of doing it every run
                        return insets;
                    
                
        );

什么是重要的。如果你有一些额外的层,如抽屉等,请将它们封装在内部而不是外部的 CoordinatorLayout,否则它会使内部的其他视图缩短 marginBottom

【讨论】:

【参考方案8】:

通过使状态栏透明,使工具栏与状态栏颜色相同,这是我所做的:

build.gradle

...
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'

**ScrollingActivity.kt**
```kt
class ScrollingActivity : AppCompatActivity(R.layout.activity_scrolling) 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setSupportActionBar(toolbar)
    

activity_scrolling.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
    android:layout_ android:layout_ android:fitsSystemWindows="true"
    tools:context=".ScrollingActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar" android:layout_ android:layout_
        android:background="#f00" android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay">

        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/toolbar" android:layout_ android:layout_
            app:popupTheme="@style/AppTheme.PopupOverlay" />
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_ android:layout_
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:layout_ android:layout_
            android:layout_margin="@dimen/text_margin" android:text="@string/large_text" />

    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

styles.xml

<resources>
    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>

    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>

清单

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.lb.myapplication">

    <application
        android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity
            android:name=".ScrollingActivity" android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

【讨论】:

【参考方案9】:

您应该将以下代码添加到您的主题中,此代码将使状态栏透明:

<item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>

此外,将滚动行为添加到顶部应用栏。以下示例显示顶部应用栏在向上滚动时消失,在向下滚动时出现:

<androidx.coordinatorlayout.widget.CoordinatorLayout
...>

<com.google.android.material.appbar.AppBarLayout
    ...>

    <com.google.android.material.appbar.MaterialToolbar
        ...
        app:layout_scrollFlags="scroll|enterAlways|snap"
        />

</com.google.android.material.appbar.AppBarLayout>
 ...
</androidx.coordinatorlayout.widget.CoordinatorLayout>

【讨论】:

【参考方案10】:

首先将这段代码添加到 AppBarLayout:

 app:liftOnScroll="true"

然后在工具栏中更新您的“app:layout_scrollFlags”:

  app:layout_scrollFlags="scroll|enterAlways|snap"

这会奏效的,我很确定。

【讨论】:

以上是关于半透明/透明状态栏 + CoordinatorLayout + Toolbar + Fragment的主要内容,如果未能解决你的问题,请参考以下文章

Android:半透明状态栏不适用于 Google Maps API

可靠获取状态栏高度解决KitKat半透明导航问题

可靠获取状态栏高度解决KitKat半透明导航问题

Android 5.0 半透明状态栏

半透明/透明状态栏 + CoordinatorLayout + Toolbar + Fragment

无法将状态栏颜色更改为半透明黑色 [重复]