Напівпрозорий шухляда навігації над рядком стану не працює


86

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

Моя панель навігації знаходиться над рядком стану, але вона не має жодної прозорості. Я перейшов за кодом із цієї публікації SO, як запропоновано у місці блогу розробників 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);
    }

Нижче наведено знімок екрана моєї шухляди для навігації, на якому показано, що верх не напівпрозорий

Знімок екрана відображає непрозорість над рядком стану


Опублікуйте скріншот результатів.
Alok Nair

@Boardy Вам вдалося змусити його працювати?
Мікеле Ла Ферла,

Неможливо встановити прозорий ефект у рядку стану. Позбавтеся від нього.
Ronak Gadhia

Відповіді:


103

Тло рядка стану біле, фон шухляди LinearLayout. Чому? Ви налаштування fitsSystemWindows="true"для вашого DrawerLayoutі LinearLayoutвсередині нього. Це призводить LinearLayoutдо розширення за рядком стану (який є прозорим). Таким чином, роблячи білим тло для панелі стану панелі стану.

введіть тут опис зображення
Якщо ви не хочете, щоб ваш шухляда виходив за рядок стану (ви хочете мати напівпрозорий фон для всього рядка стану), ви можете зробити дві речі:

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

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

введіть тут опис зображення
Якщо ви хочете, щоб ваш шухляда виходив за рядок стану та мав напівпрозоре накладання, розміром до рядка стану, ви можете використовувати a ScrimInsetFrameLayoutяк контейнер для вмісту вашого шухляди ( ListView) та встановити фон рядка стану за допомогою app:insetForeground="#4000". Звичайно, ви можете змінити #4000все, що завгодно. Не забудьте залишитися fitsSystemWindows="true"тут!

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

EDIT: Вам більше не потрібно мати справу з цим. Будь ласка, зверніться до Бібліотеки підтримки дизайну, щоб в рази спростити реалізацію навігаційного ящика / перегляду.


Спасибі за вашу допомогу. Вибачте за затримку повернення, був божевільно зайнятий. Я налаштував ще одну нагороду, щоб нагородити вашу відповідь, як я спочатку налаштував, але вона закінчилася до того, як я встиг реалізувати ваші пропозиції. На жаль, я маю почекати 23 години, на жаль, я додам його, як тільки зможу
Boardy

Обережно! З варіантами 1 або 2 обов’язково слідкуйте за перевитратами (їх можна перевірити в опціях розробника в налаштуваннях телефону). Коли я лише встановлював фон вмісту всередині, все за шухлядою теж малювалося. Інакше чудова відповідь, безумовно, заощадила мені час :)
Daiwik Daarun

1
Ви можете пояснити, яке рішення нам потрібно використовувати, використовуючи бібліотеку підтримки дизайну? У мене є деякі проблеми, навіть із відповіддю на відповідь Кріса Бейнса.
mDroidd

29

Все, що вам потрібно зробити, це використовувати якийсь напівпрозорий колір для рядка стану. Додайте ці рядки до своєї теми v21:

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

Не забувайте, що color(ресурс) завжди повинен бути у форматі #AARRGGBB. Це означає, що колір також включатиме значення альфа.


Ви той чоловік, але ... Чи можете ви сказати мені, чому це працює лише в Діяльності, яка має Шухляду? Інші, ті, хто цього не зробив, відображають сірий рядок стану.
Хоакін Ірчук

15

Чому б не використати щось подібне до цього?

<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, який, на мій погляд, легко редагується.


4
Чому ні, але незрозуміло, що ви змінюєте і як це відповідає на питання.
rds

встановіть дільник на прозорі та використані алфавітні коди у кольорі тла
Мікеле Ла Ферла

9

Усі згадані тут відповіді занадто старі та довгі. Найкраще та коротке рішення, яке працює з найновішими версіями 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"
        />

Я протестував його, і він повністю працює. Сподіваюся, це комусь допомагає. Це може бути не найкращим підходом, але він працює безперебійно і простий у реалізації. Позначте це, якщо це допоможе. Щасливого кодування :)


Дякую! Це заощадило мені багато часу. Він чудово працює з останньою NavigationView. Для тих, хто не може зробити так, щоб це працювало, переконайтеся, що ви вибрали колір із певною прозорістю для "colorPrimaryDarktrans", інакше ви не побачите жодних змін взагалі.
Руй,

Працює ідеально, єдиним недоліком є ​​те, що рядок стану «блимає», коли викликається onDrawerClosed, але якщо встановити прозорий колір colorPrimaryDarktrans на # 05000000, це майже непомітно
Кирило Кармазін,

8

Вам потрібно загорнути макет шухляди навігації всередину ScrimLayout.

В ScrimLayoutосновному малює напівпрозорий прямокутник над макетом вашого шухляди навігації. Щоб отримати розмір вставки, просто перевизначте fitSystemWindowsв ScrimLayout.

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

Пізніше перевизначте, onDrawщоб намалювати напівпрозорий прямокутник.

Приклад реалізації можна знайти в джерелі Google IO App. Тут ви можете побачити, як він використовується в макеті xml.


5

Якщо ви хочете, щоб панель навігації знаходилася над рядком стану і була напівпрозорою над рядком стану. Google I / O Android App Source надає хороше рішення ( 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>

Привіт, дякую за відповідь .. Я не можу це знайти, звідки ми отримуємо OnInsetsCallback ... Заздалегідь дякую.
Ашокхакраварті Нагараджан

Ви можете поставити ScrimInsetsView_insetForegroundатрибут.
reegan29,

1
Використання android.support.design.internal.ScrimInsetsFrameLayoutз бібліотеки підтримки
Роман

4

Я мав подібну функцію для реалізації у своєму проекті. І щоб зробити мій шухляду прозорим, я просто використовую прозорість для шестигранних кольорів . Використовуючи 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

Наприклад: якщо у вас де шестнадцятковий колір (# 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>

І ось ще одна стаття, яка може допомогти вам зрозуміти алфавітні коди у шестигранних кольорах.


1

Існуючі рішення досить застарілі. Ось найновіше рішення, яке має ідеально працювати в бібліотеках AndroidX або Material.

  • Додайте android:fitsSystemWindows="true"до кореневого подання вашого макета, який для вашого випадку є DrawerLayout.

    Це вказує View, щоб використовувати весь екран для вимірювання та розмітки, перекриваючи рядок стану.

  • Додайте наступне до свого стилю XML

      <item name="android:windowDrawsSystemBarBackgrounds">true</item>
      <item name="android:windowTranslucentStatus">true</item>
    

    windowTranslucentStatusзробить рядок стану прозорим,
    windowDrawsSystemBarBackgroundsвказує рядку стану намалювати щось під ним, замість того, щоб бути чорною порожнечею.

  • Телефонуйте DrawerLayout.setStatusBarBackground()або DrawerLayout.setStatusBarBackgroundColor()у вашій головній діяльності

    Це повідомляє DrawerLayout забарвити область рядка стану.


0

Наведені вище хороші рішення, але вони не працювали в моєму випадку,

мій випадок: у рядку стану встановлено жовтий колір, який уже використовує стилі, він не напівпрозорий. і колір моєї навігаційної шухляди білий, тепер, коли я малюю свою навігаційну шухляду, вона завжди знаходиться позаду рядка стану та панелі навігації, оскільки колір навігаційної панелі також встановлений.

мета: змінити рядок стану та колір панелі навігації, коли шухляду навігації відкрито, та відновити її назад, коли вона закрита.

рішення:

        binding.drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() 
        {
        @Override
        public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
        }

        @Override
        public void onDrawerOpened(@NonNull View drawerView) {
            getWindow().setStatusBarColor(getResources().getColor(R.color.forground));
            getWindow().setNavigationBarColor(getResources().getColor(R.color.forground));
        }

        @Override
        public void onDrawerClosed(@NonNull View drawerView) {
            getWindow().setStatusBarColor(getResources().getColor(R.color.yellow));
            getWindow().setNavigationBarColor(getResources().getColor(R.color.yellow));
        }

        @Override
        public void onDrawerStateChanged(int newState) {
        }
    });

0

Всі відповіді тут дуже складні, дозвольте мені дати вам простий простий код. Під стилем AppTheme додайте цей рядок коду, і ви отримаєте напівпрозорий сірий рядок стану, коли відкриєте шухляду.

    <item name="android:windowTranslucentStatus">true</item>

це змусить це працювати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.