[英]Put Navigation Drawer Under Status Bar
I'm trying to make my navigation drawer go under the status bar. 我正在尝试让我的导航抽屉进入状态栏。 I've read extensively about the ScrimInsetsFrameLayout view and I tried implementing it, but for some reason it won't go under.
我已经阅读了很多关于ScrimInsetsFrameLayout视图的内容,并尝试实现它,但由于某些原因它不会被删除。
Here's the code that I used/wrote. 这是我使用/编写的代码。
XML DrawerLayout: XML DrawerLayout:
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include layout="@layout/toolbar" />
</FrameLayout>
<com.andrewq.planets.util.ScrimInsetsFrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/linearLayout"
android:layout_width="304dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:insetForeground="#4000">
<ListView
android:id="@+id/left_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="singleChoice" />
</com.andrewq.planets.util.ScrimInsetsFrameLayout>
</android.support.v4.widget.DrawerLayout>
ScrimInsetsFrameLayout.java: ScrimInsetsFrameLayout.java:
package com.andrewq.planets.util;
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import com.andrewq.planets.R;
/**
* A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome
* (status and navigation bars, overlay action bars).
*/
public class ScrimInsetsFrameLayout extends FrameLayout {
private Drawable mInsetForeground;
private Rect mInsets;
private Rect mTempRect = new Rect();
private OnInsetsCallback mOnInsetsCallback;
public ScrimInsetsFrameLayout(Context context) {
super(context);
init(context, null, 0);
}
public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ScrimInsetsView, defStyle, 0);
if (a == null) {
return;
}
mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsView_insetForeground);
a.recycle();
setWillNotDraw(true);
}
@Override
protected boolean fitSystemWindows(Rect insets) {
mInsets = new Rect(insets);
setWillNotDraw(mInsetForeground == null);
ViewCompat.postInvalidateOnAnimation(this);
if (mOnInsetsCallback != null) {
mOnInsetsCallback.onInsetsChanged(insets);
}
return true; // consume insets
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
int width = getWidth();
int height = getHeight();
if (mInsets != null && mInsetForeground != null) {
int sc = canvas.save();
canvas.translate(getScrollX(), getScrollY());
// Top
mTempRect.set(0, 0, width, mInsets.top);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Bottom
mTempRect.set(0, height - mInsets.bottom, width, height);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Left
mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Right
mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
canvas.restoreToCount(sc);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mInsetForeground != null) {
mInsetForeground.setCallback(this);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mInsetForeground != null) {
mInsetForeground.setCallback(null);
}
}
/**
* Allows the calling container to specify a callback for custom processing when insets change (i.e. when
* {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on
* UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set
* clipToPadding to false.
*/
public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
mOnInsetsCallback = onInsetsCallback;
}
public static interface OnInsetsCallback {
public void onInsetsChanged(Rect insets);
}
}
And finally, here's my styles.xml for values-v21: 最后,这是我的styles.xml for values-v21:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppThemeNavDrawer" parent="Theme.AppCompat.NoActionBar">
<item name="colorAccent">#F8F8F8</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
I've looked at the 2014 I/O app source code as well as this question, and I don't know what is so different. 我查看了2014 I / O应用程序源代码以及这个问题,我不知道有什么不同。
Here's a screenshot of what I have so far minus the drawer under the status bar: 这是我到目前为止的截图,减去状态栏下的抽屉:
I've got everything else working perfectly and this is the last thing I need to do. 我已经完成了其他一切工作,这是我需要做的最后一件事。 Help is greatly appreciated!
非常感谢帮助!
To clarify, I want to have the image be tinted under the status bar just like in most of the Google Apps and Google Now. 为了澄清,我想让图像在状态栏下着色,就像大多数Google Apps和Google Now一样。
将android:fitsSystemWindows="false"
到DrawerLayout将解决问题
There are different approaches to get to the desired result. 有不同的方法来达到预期的结果。 You can enable translucent via style or via code.
您可以通过样式或代码启用半透明。
I've created a MaterialDrawer (which follows the Android Material Design Guidelines) which implements all of this and handles everything for you. 我创建了一个MaterialDrawer(遵循Android Material Design Guidelines),它实现了所有这些并为您处理所有事情。 Read more here: https://github.com/mikepenz/MaterialDrawer/
在这里阅读更多内容: https : //github.com/mikepenz/MaterialDrawer/
If you want to create it on your own you always have to decide which is the lowest api you want to support and/or if you have to split up your styles. 如果你想自己创建它,你总是要决定哪个是你想要支持的最低api和/或你是否需要拆分你的样式。
So to enable translucentStatusbar you have to be at least on API v19 or you create a separat style for v19+ values-v19
This will look somehow like this 因此,要启用translucentStatusbar,您必须至少在API v19上,或者为v19 +
values-v19
创建一个分离样式。这看起来有点像这样
<style name="YourTheme.TranslucentStatus" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowTranslucentStatus">true</item>
</style>
So now this will move your complete layout below the statusbar. 所以现在这将把你的完整布局移到状态栏下面。 In almost all cases you will now want to add the padding on the top of the drawer content and your normal view content.
几乎在所有情况下,您现在都想在抽屉内容和普通视图内容的顶部添加填充。
You can do this by adding 24dp
padding. 您可以通过添加
24dp
填充来完成此24dp
。
This is not a really nice implementation. 这不是一个非常好的实现。 So there's a different approach by using the ScrimInsetsLayout which is used in the Google IO 2014 app.
因此,使用Google IO 2014应用中使用的ScrimInsetsLayout有不同的方法。 https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/ScrimInsetsFrameLayout.java
https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/ScrimInsetsFrameLayout.java
This will be your contents layout and you can set the color for the statusbar on it. 这将是您的内容布局,您可以在其上设置状态栏的颜色。 You can find a detailed instruction, on how you can use it, here: https://stackoverflow.com/a/26932228
您可以在此处找到有关如何使用它的详细说明: https : //stackoverflow.com/a/26932228
It requires some time to get used to the styles and / or the ScrimInsetsLayout
. 它需要一些时间来习惯样式和/或
ScrimInsetsLayout
。
EDIT: 编辑:
A more complex sample on how you can handle this programmatically: 有关如何以编程方式处理此问题的更复杂示例:
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
//enable translucent statusbar via flags
setTranslucentStatusFlag(true);
}
if (Build.VERSION.SDK_INT >= 19) {
mActivity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
if (Build.VERSION.SDK_INT >= 21) {
//we don't need the translucent flag this is handled by the theme
setTranslucentStatusFlag(false);
//set the statusbarcolor transparent to remove the black shadow
mActivity.getWindow().setStatusBarColor(Color.TRANSPARENT);
}
//add a padding to the content of the drawer (25dp on devices starting with api v19)
mDrawerContentRoot.setPadding(0, mActivity.getResources().getDimensionPixelSize(R.dimen.tool_bar_top_padding), 0, 0);
// define the statusBarColor
mDrawerContentRoot.setInsetForeground(mStatusBarColor);
private void setTranslucentStatusFlag(boolean on) {
if (Build.VERSION.SDK_INT >= 19) {
Window win = mActivity.getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
}
EDIT2: EDIT2:
The complete solution to fix this issue was to clean up all the layouts which were in the project. 解决此问题的完整解决方案是清理项目中的所有布局。 some combination of the layouts and styles were causing the troubles.
布局和样式的某种组合导致了麻烦。
The complete changes can be found in this pull request: https://github.com/Andrew-Quebe/Planets-Gradle/commit/83e28c09253af6e807b6f4e94baca8fbca3fc7c8 完整的更改可以在此拉取请求中找到: https : //github.com/Andrew-Quebe/Planets-Gradle/commit/83e28c09253af6e807b6f4e94baca8fbca3fc7c8
You need to make a new styles.xml and put that file in style-v19 folder because the status bar translucent method is not available for pre kitkat devices. 您需要创建一个新的styles.xml并将该文件放在style-v19文件夹中,因为状态栏半透明方法不适用于pre kitkat设备。
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar" >
<item name="android:windowTranslucentStatus">true</item>
</style>
After that you will see the your Application is under the Status bar But you need to give padding to toolBar for the Exact implementation.Create a dimen-v19 and add 之后,您将看到您的应用程序位于状态栏下但您需要为工具栏提供填充以进行精确实现。创建一个维度-v19并添加
<dimen name="ToolBarPaddingTop">24dp</dimen>
Use it in ToolBar 在ToolBar中使用它
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/accent_material_light"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:fitsSystemWindows="true"
android:paddingTop="@dimen/ToolBarPaddingTop">
</android.support.v7.widget.Toolbar>
This is what worked for me: 这对我有用:
android:windowTranslucentStatus
to true
in your default style in the v21 folder. android:windowTranslucentStatus
设置为true
。 This will make your statusbar almost transparent from Lollipop. Toolbar
with the android:colorPrimary
parameter in your style. android:colorPrimary
参数定义Toolbar
的颜色。 android:fitsSystemWindows="true"
in your layout. android:fitsSystemWindows="true"
。 Toolbar
and Drawer
. Toolbar
和Drawer
上使用它。 我相信你需要将android:fitsSystemWindows="true"
到android.support.v4.widget.DrawerLayout
标签中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.