把抽屉式导航栏在状态栏状态栏、抽屉式

2023-09-05 04:43:19 作者:凉不过人心

我试图让我的抽屉式导航去下状态栏中。我广泛阅读有关ScrimInsetsFrameLayout看法,我尝试推行,但由于某种原因,它不会去下。

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.

这里的code,我用/写。

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);
    }
}

最后,这里是我的styles.xml的价值观V21:

And finally, here's my 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>

我已经看了2014年的I / O的应用程序源$ C ​​$ C,以及this的问题,我不知道什么是如此不同。

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.

下面是什么,我至今截图减去下状态栏中的抽屉:

Here's a screenshot of what I have so far minus the drawer under the status bar:

我已经得到了一切可以正常使用,这是我需要做的最后一件事。帮助是极大的AP preciated!

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.

推荐答案

有不同的方法来得到所期望的结果。您可以通过风格或通过code启用半透明。

There are different approaches to get to the desired result. You can enable translucent via style or via code.

我创建了一个MaterialDrawer(它遵循了Android材料设计指南),它实现了这一切,并处理一切为您服务。在这里阅读更多:https://github.com/mikepenz/MaterialDrawer/

I've created a MaterialDrawer (which follows the Android Material Design Guidelines) which implements all of this and handles everything for you. Read more here: https://github.com/mikepenz/MaterialDrawer/

如果你想在自己创建你总是必须决定是要支持的最低API和/或如果你有分裂的风格。

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.

因此​​,为了使translucentStatusbar你必须至少在API V19或创建一个分隔符样式V19 + 值-V19 这看起来在某种程度上是这样

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

<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.

您可以通过添加 24dp 填充做到这一点。

You can do this by adding 24dp padding.

这是不是一个非常好的实现。因此,有一种不同的方法通过使用用于在谷歌的IO 2014的应用程序的ScrimInsetsLayout。 https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/ScrimInsetsFrameLayout.java

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. https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/ScrimInsetsFrameLayout.java

这将是你的内容布局,可以设置它的状态栏的颜色。你可以找到详细的说明,关于如何使用它,在这里: http://stackoverflow.com/a/26932228

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: http://stackoverflow.com/a/26932228

这需要一些时间来习惯的风格和/或 ScrimInsetsLayout

It requires some time to get used to the styles and / or the ScrimInsetsLayout.

编辑:

你如何处理这个编程的一个更复杂的示例:

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:

完整的解决方案来解决这一问题是清理所有这些都是在项目的布局。布局和样式的组合是造成麻烦。

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.

完整的变化可以在此拉动请求中发现: https://github.com/Andrew-Quebe/Planets-Gradle/commit/83e28c09253af6e807b6f4e94baca8fbca3fc7c8

The complete changes can be found in this pull request: https://github.com/Andrew-Quebe/Planets-Gradle/commit/83e28c09253af6e807b6f4e94baca8fbca3fc7c8