it-swarm.com.ru

Ящик навигации полупрозрачный над строкой состояния не работает

Я работаю над проектом Android и ​​реализую Навигационный ящик. Я читаю новые Спецификация дизайна материала и Контрольный список материалов .
В спецификации сказано, что выдвижная панель должна располагаться над всем остальным, включая строку состояния, и быть полупрозрачной над строкой состояния.

Моя панель навигации находится над строкой состояния, но не имеет прозрачности. Я следовал коду из этой ТАК публикации, как это было предложено в блоге разработчиков Google, ссылка выше Как использовать DrawerLayout отображать поверх панели инструментов/панели инструментов и под строкой состояния? .

Ниже мой XML-макет

<Android.support.v4.widget.DrawerLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/my_drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true">
    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:orientation="vertical">
        <Android.support.v7.widget.Toolbar
            Android:id="@+id/my_awesome_toolbar"
            Android:layout_height="wrap_content"
            Android:layout_width="match_parent"
            Android:minHeight="?attr/actionBarSize"
            Android:background="@color/appPrimaryColour" />
    </LinearLayout>
    <LinearLayout Android:id="@+id/linearLayout"
        Android:layout_width="304dp"
        Android:layout_height="match_parent"
        Android:layout_gravity="left|start"
        Android:fitsSystemWindows="true"
        Android:background="#ffffff">
        <ListView Android:id="@+id/left_drawer"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:choiceMode="singleChoice"></ListView>
    </LinearLayout>
</Android.support.v4.widget.DrawerLayout>

Ниже приведена тема моих приложений

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/appPrimaryColour</item>
        <item name="colorPrimaryDark">@color/appPrimaryColourDark</item>
        <item name="colorAccent">@color/appPrimaryColour</item>
        <item name="windowActionBar">false</item>
        <item name="windowActionModeOverlay">true</item>

    </style>

Ниже приведена тема моих приложений v21

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/appPrimaryColour</item>
    <item name="colorPrimaryDark">@color/appPrimaryColourDark</item>
    <item name="colorAccent">@color/appPrimaryColour</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>

Ниже мой метод onCreate

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
    setSupportActionBar(toolbar);

    mDrawerLayout = (DrawerLayout)findViewById(R.id.my_drawer_layout);
    mDrawerList = (ListView)findViewById(R.id.left_drawer);

    mDrawerLayout.setStatusBarBackgroundColor(
        getResources().getColor(R.color.appPrimaryColourDark));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop)
    {
        LinearLayout linearLayout = 
            (LinearLayout)findViewById(R.id.linearLayout);
        linearLayout.setElevation(30);
    }

Ниже снимок экрана моего навигационного ящика, показывающий, что верхняя часть экрана не полупрозрачна

Screenshot showing non transparent over the status bar

80
Boardy

Ваш фон строки состояния белый, фон вашего ящика LinearLayout. Зачем? У вас есть настройки fitsSystemWindows="true" для вашего DrawerLayout и LinearLayout внутри него. Это заставляет ваше LinearLayout расширяться за строкой состояния (которая прозрачна). Таким образом, делая фон для ящика частью строки состояния белым.

enter image description here
Если вы не хотите, чтобы ваш ящик выдвигался за строку состояния (хотите иметь полупрозрачный фон для всей строки состояния), вы можете сделать две вещи:

1) Вы можете просто удалить любое значение фона из своего LinearLayout и покрасить фон вашего контента внутри него. Или же

2) Вы можете удалить fitsSystemWindows="true" из своего LinearLayout. Я думаю, что это более логичный и более чистый подход. Вы также избежите отбрасывания тени под строкой состояния, где ваш ящик навигации не расширяется.

enter image description here
Если вы хотите, чтобы ваш ящик выдвигался за строкой состояния и имел полупрозрачный оверлей размера строки состояния, вы можете использовать ScrimInsetFrameLayout в качестве контейнера для содержимого вашего ящика (ListView) и установите фон строки состояния, используя app:insetForeground="#4000". Конечно, вы можете изменить #4000 на что угодно. Не забудьте оставить здесь fitsSystemWindows="true"!

Или, если вы не хотите накладывать свой контент и отображать только сплошной цвет, вы можете просто установить фон вашего LinearLayout на любое значение. Не забудьте установить фон вашего контента отдельно!

РЕДАКТИРОВАТЬ: Вам больше не нужно иметь дело с этим. Пожалуйста, смотрите Библиотека поддержки проектирования для упрощения реализации Навигационного Ящика/Представления.

97
xip

Все, что вам нужно сделать, это использовать полупрозрачный цвет для строки состояния. Добавьте эти строки в тему v21:

<item name="Android:windowDrawsSystemBarBackgrounds">true</item>
<item name="Android:statusBarColor">@color/desired_color</item>

Не забывайте, что color (ресурс) всегда должен быть в формате #AARRGGBB. Это означает, что цвет будет также включать альфа-значение.

29
mroczis

Почему бы не использовать что-то похожее на это?

<Android.support.v4.widget.DrawerLayout
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:id="@+id/drawer_layout"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        >

    <FrameLayout
            Android:id="@+id/content_frame"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"/>

    <ListView
            Android:id="@+id/left_drawer"
            Android:layout_width="240dp"
            Android:layout_height="match_parent"
            Android:layout_gravity="start"
            Android:choiceMode="singleChoice"
            Android:divider="@Android:color/transparent"
            Android:dividerHeight="0dp"
            Android:background="#80111111"/>
</Android.support.v4.widget.DrawerLayout>

Приведенный выше код использует альфа-ресурс в Android:background, чтобы показать прозрачность в панели действий.

Есть другие способы сделать это через код, как показывают другие ответы. Мой ответ выше, делает все необходимое в файле макета XML, который на мой взгляд легко редактируется.

15
Michele La Ferla

Вам нужно обернуть свой макет навигационного ящика внутри ScrimLayout.

ScrimLayout в основном рисует полупрозрачный прямоугольник над макетом вашего навигационного ящика. Чтобы получить размер вставки, просто переопределите fitSystemWindows в вашем ScrimLayout.

@Override
protected boolean fitSystemWindows(Rect insets) {
    mInsets = new Rect(insets);
    return true;
}

Позже переопределите onDraw, чтобы нарисовать полупрозрачный прямоугольник.

Реализацию пример можно найти в источнике приложения Google IO. Здесь вы можете увидеть, как он используется в макете XML.

8
markus-hi

Все упомянутые здесь ответы слишком стары и длинны. Лучшее и краткое решение, которое работает с последним Navigationview, это

@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
    super.onDrawerSlide(drawerView, slideOffset);

    try {
        //int currentapiVersion = Android.os.Build.VERSION.SDK_INT;
        if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop){
            // Do something for Lollipop and above versions

        Window window = getWindow();

        // clear FLAG_TRANSLUCENT_STATUS flag:
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

        // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

        // finally change the color to any color with transparency

         window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDarktrans));}

    } catch (Exception e) {

        Crashlytics.logException(e);

    }
}

это изменит цвет строки состояния на прозрачный при открытии ящика

Теперь, когда вы закрываете ящик, вам нужно снова изменить цвет строки состояния на темный. Так что вы можете сделать это таким образом.

@Override
public void onDrawerClosed(View drawerView) {
   super.onDrawerClosed(drawerView);
    try {
        if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop) {
            // Do something for Lollipop and above versions

            Window window = getWindow();

            // clear FLAG_TRANSLUCENT_STATUS flag:
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

            // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

            // finally change the color again to dark
            window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
        }
    } catch (Exception e) {
        Crashlytics.logException(e);
    }
}

а затем в основной макет добавить одну строку, т.е.

            Android:fitsSystemWindows="true"

и ваш макет ящика будет выглядеть

            <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:fitsSystemWindows="true"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent">

и ваш вид навигации будет выглядеть

    <Android.support.design.widget.NavigationView
        Android:id="@+id/navigation_view"
        Android:layout_height="match_parent"
        Android:layout_width="wrap_content"
        Android:layout_gravity="start"
        Android:fitsSystemWindows="true"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/drawer"
        />

Я проверил его, и он полностью работает. Надеюсь, он кому-нибудь поможет. Это может быть не самый лучший подход, но он работает гладко и прост в реализации. Пометьте, если это поможет. Счастливое кодирование :)

6
Harry Sharma

Если вы хотите, чтобы панель навигации находилась над строкой состояния и была полупрозрачной над строкой состояния. Google I/O Android Источник приложения предоставляет хорошее решение ( APK в Play Store не обновлены до продолжительной версии)

Сначала вам нужно ScrimInsetFrameLayout

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

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

Затем в вашем XML-макете измените эту часть

<LinearLayout Android:id="@+id/linearLayout"
    Android:layout_width="304dp"
    Android:layout_height="match_parent"
    Android:layout_gravity="left|start"
    Android:fitsSystemWindows="true"
    Android:background="#ffffff">
    <ListView Android:id="@+id/left_drawer"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:choiceMode="singleChoice"></ListView>
</LinearLayout>

Измените LinearLayout на свой ScrimInsetFrameLayout следующим образом

<com.boardy.util.ScrimInsetFrameLayout
    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="left|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"></ListView>
</com.boardy.util.ScrimInsetFrameLayout>
5
skyfishjy

У меня была похожая функция для реализации в моем проекте. И чтобы сделать мой ящик прозрачным, я просто использую прозрачность для шестнадцатеричных цветов . Используя 6 шестнадцатеричных цифр, у вас есть 2 шестнадцатеричные цифры для каждого значения красного, зеленого и синего соответственно. но если вы добавите две дополнительные цифры (8 шестнадцатеричных цифр), то у вас будет ARGB (две цифры для альфа-значения) ( смотрите здесь ).

Вот шестнадцатеричные значения непрозрачности: для 2 дополнительных цифр

100% — FF
95% — F2
90% — E6
85% — D9
80% — CC
75% — BF
70% — B3
65% — A6
60% — 99
55% — 8C
50% — 80
45% — 73
40% — 66
35% — 59
30% — 4D
25% — 40
20% — 33
15% — 26
10% — 1A
5% — 0D
0% — 00

Например: если у вас есть цвет de hex (# 111111), просто поместите одно из значений непрозрачности, чтобы получить прозрачность. как это: (# 11111100)

Мой ящик не закрывает панель действий (как у вас), но прозрачность может быть применена и в этих случаях. Вот мой код:

     <ListView
          Android:id="@+id/left_drawer"
          Android:layout_width="240dp"
          Android:layout_height="match_parent"
          Android:layout_gravity="start"
          Android:background="#11111100"
          Android:choiceMode="singleChoice"
          Android:divider="@Android:color/transparent"
          Android:dividerHeight="0dp" />
</Android.support.v4.widget.DrawerLayout>

А вот еще одна статья , которая может помочь вам понять альфа-коды в шестнадцатеричных цветах.

4
fdsilva