Pytanie Szuflada nawigacji półprzezroczysta nad wskaźnikiem stanu nie działa


Pracuję nad projektem Android i wdrażam szufladę nawigacji. Czytam nowe Material Design Spec i Lista kontrolna materiałów budowlanych.
Specyfikacja mówi, że panel slajdów powinien unosić się nad wszystkim innym, w tym na pasku stanu i być półprzezroczysty na pasku stanu.

Mój panel nawigacyjny znajduje się nad paskiem stanu, ale nie ma żadnej przezroczystości. Śledziłem kod z tego WIĘC post zgodnie z sugestią w blogu programisty Google, link powyżej Jak używać DrawerLayout do wyświetlania na pasku akcji / pasku narzędzi i pod paskiem stanu?.

Poniżej znajduje się mój układ 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>

Poniżej znajduje się mój motyw aplikacji

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

Poniżej znajduje się motyw mojej aplikacji 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>

Poniżej znajduje się moja metoda 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);
    }

Poniżej znajduje się zrzut ekranu mojej szuflady nawigacyjnej pokazującej wierzchołek nie jest półprzezroczysta

Screenshot showing non transparent over the status bar


76
2017-11-04 21:23


pochodzenie


Opublikuj zrzut ekranu swoich wyników. - Alok Nair
@AlokNair Zaktualizowałem moje pytanie, aby dołączyć zrzut ekranu - Boardy
@Boardy czy udało ci się go uruchomić? - dev.mi
To pytanie rozwiązało mój problem :-) - Tinashe
Nie można ustawić efektu przezroczystego w pasku stanu. Pozbądź się go. - Ronak Gadhia


Odpowiedzi:


Twoje tło paska stanu jest białe, tło Twojej szuflady LinearLayout. Czemu? Jesteś ustawienia fitsSystemWindows="true" dla Twojego DrawerLayout i LinearLayout w środku tego. To powoduje twoją LinearLayout rozszerzać za pasek stanu (który jest przezroczysty). W ten sposób, aby tło dla części szuflady paska stanu było białe.

enter image description here
Jeśli nie chcesz, aby szuflada wysuwała się poza pasek stanu (chcesz mieć półprzezroczyste tło dla całego paska stanu), możesz zrobić dwie rzeczy:

1) Możesz po prostu usunąć dowolną wartość tła z twojego LinearLayout i pokoloruj tło swojej zawartości. Lub

2) Możesz usunąć fitsSystemWindows="true" od twojego LinearLayout. Myślę, że jest to bardziej logiczne i czystsze podejście. Unikasz również rzucania cienia pod pasek stanu, gdzie szuflada nawigacji nie wysuwa się.

enter image description here
Jeśli chcesz, aby szuflada wysuwała się poza pasek stanu i ma półprzezroczystą nakładkę rozmiaru paska stanu, możesz użyć znaku a ScrimInsetFrameLayout jako pojemnik na zawartość Twojej szuflady (ListView) i ustaw tło paska stanu za pomocą app:insetForeground="#4000". Oczywiście możesz zmienić #4000 do wszystkiego, co chcesz. Nie zapomnij zachować fitsSystemWindows="true" tutaj!

Lub jeśli nie chcesz nakładać treści i wyświetlać tylko jednolity kolor, możesz po prostu ustawić tło swojego LinearLayout do wszystkiego, co chcesz. Nie zapomnij jednak ustawić tła treści oddzielnie!

EDYTOWAĆ: Nie musisz już zajmować się tym. Proszę zobaczyć Biblioteka wsparcia projektowania na nieco łatwiejszą nawigację Szuflada / Widok realizacji.


95
2017-11-14 14:27



Dzięki za pomoc. Przepraszam za opóźnienie w powrocie, szalenie zajęty. Skonfigurowałem kolejną nagrodę, aby nagrodzić twoją odpowiedź, jak początkowo ustawiłem, ale skończyło się, zanim zdążyłem wprowadzić twoje sugestie. Muszę czekać niestety 23 godziny, więc dodam je tak szybko, jak tylko będę mógł - Boardy
Uwaga! Przy opcjach 1 lub 2 pamiętaj, aby obserwować wyprzedaże (możesz je sprawdzić w opcjach dewelopera w ustawieniach telefonu). Gdy tylko ustawiłem tło zawartości wewnątrz wszystkiego, za szufladą również się rysowało. W przeciwnym razie świetna odpowiedź, zdecydowanie mnie uratowała :) - Daiwik Daarun
Czy możesz wyjaśnić, z jakiego rozwiązania musimy skorzystać przy użyciu biblioteki wsparcia projektu? Mam pewne problemy, nawet z odpowiedzią, którą opublikował Chris Banes. - mDroidd


Wszystko, co musisz zrobić, to użyć półprzezroczystego koloru na pasku stanu. Dodaj te linie do swojego motywu v21:

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

Nie zapominaj, że color (zasób) musi zawsze mieć format #AARRGGBB. Oznacza to, że kolor będzie również zawierał wartość alfa.


29
2017-11-05 20:52



Thnks, ale mam już to w moim V21 - Boardy
Jesteś mężczyzną, ale ... Czy możesz mi powiedzieć, dlaczego to działa tylko w Aktywności, która ma Szufladę? Inni, ci, którzy tego nie robią, pokazują szary pasek statusu. - Joaquin Iurchuk


Dlaczego nie użyć czegoś podobnego do tego?

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

Powyższy kod używa zasobu alfa w android:background aby pokazać przezroczystość na pasku akcji.

Są inne sposoby na zrobienie tego za pomocą kodu, jak pokazują inne odpowiedzi. Moja odpowiedź powyżej, jest niezbędna w pliku układu XML, który moim zdaniem można łatwo edytować.


15
2017-11-11 12:27



Dlaczego nie, ale nie jest jasne, co się zmienia i jak to odpowiada na pytanie. - rds
ustaw dzielnik na przezroczysty i używaj kodów alfa w kolorze tła - dev.mi


Musisz zawinąć układ szuflady nawigacji wewnątrz ScrimLayout.

ZA ScrimLayout zasadniczo rysuje półprzezroczysty prostokąt nad układem szuflady nawigacji. Aby uzyskać rozmiar wkładki, wystarczy przesłonić fitSystemWindows w Twoim ScrimLayout.

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

Później zastąp onDraw narysować półprzezroczysty prostokąt.

Na przykład wdrożenie można znaleźć w źródle aplikacji Google IO. Tutaj możesz zobaczyć, jak jest on wykorzystywany w układzie xml.


8
2017-11-14 09:43





Jeśli chcesz, aby panel nawigacyjny znajdował się nad paskiem stanu i był półprzezroczysty na pasku stanu. Źródło aplikacji Google na Androida I / O stanowi dobre rozwiązanie (APK w Sklepie Play nie są aktualizowane do wersji trwającej)

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

Następnie w swoim układzie XML zmień tę część

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

Zmień LinearLayout na ScrimInsetFrameLayout w ten sposób

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

6
2017-11-15 08:49



Cześć, dziękuję za odpowiedź .. Nie mogę tego znaleźć, skąd otrzymujemy OnInsetsCallback ... Z góry dziękujemy. - Ashok Chakravarthi
czy możesz umieścić ScrimInsetsView_insetForeground atrybut . - reegan29
Posługiwać się android.support.design.internal.ScrimInsetsFrameLayout z biblioteki wsparcia - Roman
@Roman Używanie ScrimInsetsFrameLayout z biblioteki wsparcia rozwiązało problem tutaj dla mnie. Wielkie dzięki. - Aritra Roy


Miałem podobną funkcję do wdrożenia w moim projekcie. I żeby moja szuflada była przezroczysta, używam tylko przezroczystość dla kolorów szesnastkowych. Używając 6 cyfr szesnastkowych, masz 2 cyfry heksadecymalne dla każdej wartości odpowiednio czerwonego, zielonego i niebieskiego. ale jeśli umieścisz dwie dodatkowe cyfry (8 cyfr szesnastkowych), więc masz ARGB (dwie cyfry dla wartości alfa) (Popatrz tutaj).

Oto wartości opacity hex: dla 2 dodatkowych cyfr

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

Na przykład: jeśli masz kolor de hex (# 111111), po prostu umieść jedną z wartości nieprzezroczystości, aby uzyskać przezroczystość. tak: (# 11111100)

Moja szuflada nie obejmuje paska działań (takiego jak twój), ale przezroczystość może być również zastosowana w tych przypadkach. Oto mój kod:

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

A tu jest inny artykuł które mogą pomóc ci zrozumieć kody alfa w kolorach szesnastkowych.


4
2017-11-14 13:24





Wszystkie wymienione tutaj odpowiedzi są zbyt stare i długie. Najlepsze i krótkie rozwiązanie, które współpracuje z najnowszym systemem nawigacji

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

    }
}

to zmieni kolor paska stanu na przezroczysty po otwarciu szuflady

Teraz po zamknięciu szuflady należy ponownie zmienić kolor paska statusu na ciemny. Można to zrobić w ten sposób.

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

a następnie w głównym układzie dodaj pojedynczą linię, tj

            android:fitsSystemWindows="true"

a twój układ szuflad będzie wyglądał

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

a twój widok nawigacyjny będzie wyglądał

    <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"
        />

Przetestowałem to i jego w pełni działa. Mam nadzieję, że pomaga komuś. To może nie być najlepsze podejście, ale działa sprawnie i jest łatwe do wdrożenia. Oznacz to, jeśli pomoże. Dobre kodowanie :)


2
2018-02-12 12:28



Nie działa. :( - Aks4125
Dzięki! To zaoszczędziło mi dużo czasu. Działa idealnie z najnowszym NavigationView. Dla każdego, kto nie może tego zrobić, upewnij się, że wybrałeś kolor z przezroczystością dla "colorPrimaryDarktrans", w przeciwnym razie nie zobaczysz żadnej zmiany. - Rui
Działa doskonale, jedyną wadą jest to, że pasek statusu "miga", gdy wywoływana jest funkcja onDrawerClosed, ale jeśli ustawisz przezroczysty kolor colorPrimaryDarktrans na # 05000000, jest on prawie niezauważalny - Kirill Karmazin
@KirillKarmazin upvote jeśli to pomogło :) - Harry Sharma