Jak korzystać z DrawerLayout, aby wyświetlać się nad paskiem narzędzi / paskiem narzędzi i pod paskiem stanu?

394

Widziałem w nowej specyfikacji materiału Side Nav , że możesz wyświetlać szufladę nad paskiem akcji i za paskiem stanu. Jak mogę to zaimplementować?

Chris Banes
źródło
4
Nawet dzisiaj nie ma jednoznacznej odpowiedzi, która działałaby z kompatybilnością wsteczną. Tego rodzaju problemy naprawdę denerwują każdego programistę. Już promuję interfejs API „N” i wiele innych podstawowych aspektów do ulepszenia w systemie Android.
Val Martinez

Odpowiedzi:

528

Nowe funkcje w ramach i biblioteki wsparcia pozwalają na to dokładnie. Istnieją trzy „elementy układanki”:

  1. Używanie paska narzędzi do osadzania paska akcji w hierarchii widoku.
  2. Tworzenie szuflady fitsSystemWindows tak, aby układała się za paskami systemowymi.
  3. Wyłączenie Theme.Materialnormalnego kolorowania paska stanu, aby DrawerLayout mógł tam rysować.

Zakładam, że będziesz używać nowego appcompat.

Po pierwsze, twój układ powinien wyglądać następująco:

<!-- The important thing to note here is the added fitSystemWindows -->
<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">

    <!-- Your normal content view -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!-- We use a Toolbar so that our drawer can be displayed
             in front of the action bar -->
        <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="?attr/colorPrimary" />

        <!-- The rest of your content view -->

    </LinearLayout>

    <!-- Your drawer view. This can be any view, LinearLayout
         is just an example. As we have set fitSystemWindows=true
         this will be displayed under the status bar. -->
    <LinearLayout
        android:layout_width="304dp"
        android:layout_height="match_parent"
        android:layout_gravity="left|start"
        android:fitsSystemWindows="true">

        <!-- Your drawer content -->

    </LinearLayout>

</android.support.v4.widget.DrawerLayout>

Następnie w swojej aktywności / fragmencie:

public void onCreate(Bundled savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Your normal setup. Blah blah ...

    // As we're using a Toolbar, we should retrieve it and set it
    // to be our ActionBar
    Toolbar toolbar = (...) findViewById(R.id.my_awesome_toolbar);
    setSupportActionBar(toolbar);

    // Now retrieve the DrawerLayout so that we can set the status bar color.
    // This only takes effect on Lollipop, or when using translucentStatusBar
    // on KitKat.
    DrawerLayout drawerLayout = (...) findViewById(R.id.my_drawer_layout);
    drawerLayout.setStatusBarBackgroundColor(yourChosenColor);
}

Następnie upewnij się, że DrawerLayout jest widoczny za paskiem stanu. Robisz to, zmieniając motyw wartości v21:

wartości-v21 / themes.xml

<style name="Theme.MyApp" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:windowTranslucentStatus">true</item>
</style>

Uwaga: Jeśli <fragment android:name="fragments.NavigationDrawerFragment">zamiast

<LinearLayout
    android:layout_width="304dp"
    android:layout_height="match_parent"
    android:layout_gravity="left|start"
    android:fitsSystemWindows="true">

    <!-- Your drawer content -->

</LinearLayout>

rzeczywisty układ, pożądany efekt zostanie osiągnięty, jeśli wywołasz fitsSystemWindows(boolean)widok, który powrócisz z onCreateViewmetody.

@Override
public View onCreateView(LayoutInflater inflater, 
                         ViewGroup container,
                         Bundle savedInstanceState) {
    View mDrawerListView = inflater.inflate(
        R.layout.fragment_navigation_drawer, container, false);
    mDrawerListView.setFitsSystemWindows(true);
    return mDrawerListView;
}
Chris Banes
źródło
3
Tak, DrawerLayoutnależy go rozłożyć za paskami systemowymi. Następnie należy ustawić go w widoku szuflady, aby DrawerLayoutukładał się w wstawkach okien.
Chris Banes
11
Nie mogę tego w ogóle zadziałać. Dzięki powyższemu kodowi w nowej aplikacji demonstracyjnej wynik wygląda podobnie do opisanego przez @ScootrNova. Zobacz zrzut
Michael Schmidt
6
Wygląda na to, że faktycznie musisz użyć negatywu layout_marginTopw katalogu głównym układu zawartości szuflady. W przeciwnym razie tło układu zawartości szuflady zostanie narysowane na pasku stanu, a wszystko inne zostanie przesunięte w dół. Wydaje się to jednak dość rażącym rozwiązaniem, o ile wiem, że nie ma? Attr / statusBarSize ani niczego takiego dostarczonego przez Androida.
Charles Madere
26
Aby uzyskać efekt, w którym szuflada jest widoczna przez pasek stanu, skończyłem na ustawianiu Androida: fitsSystemWindows na false na DrawerLayout, android: fitsSystemWindows na true na moim głównym układzie zawartości (układ zawierający pasek narzędzi) i dodawanie <nazwy elementu = "android: windowTranslucentStatus"> true </item> do mojego motywu - na Lollipop, czyli
Jakob
8
Ta odpowiedź jest niepełna. Musisz także owinąć szufladę nawigacji w ScrimLayout. Patrz stackoverflow.com/a/26926998/174149
Markus Hi
138

EDYCJA: Nowa biblioteka wsparcia projektowania obsługuje to, a poprzednia metoda nie jest już wymagana.

Można to teraz osiągnąć za pomocą nowej biblioteki wsparcia projektowania systemu Android .

Możesz zobaczyć przykładową aplikację Cheesesquare autorstwa Chrisa Banesa, która demonstruje wszystkie nowe funkcje.


Poprzednia metoda:

Ponieważ nie ma opublikowanego kompletnego rozwiązania, oto sposób, w jaki osiągnąłem pożądany rezultat.

Najpierw dołącz ScrimInsetsFrameLayout do swojego projektu.

/*
* 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 utwórz stylowy, aby insetForegroundmożna go było ustawić.

wartości / attrs.xml

<declare-styleable name="ScrimInsetsView">
    <attr name="insetForeground" format="reference|color" />
</declare-styleable>

Zaktualizuj plik xml swojej aktywności i upewnij się, że android:fitsSystemWindowsjest ustawiony na true zarówno w, DrawerLayoutjak i w pliku ScrimInsetsFrameLayout.

layout / activity_main.xml

<android.support.v4.widget.DrawerLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <!-- The main content view -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!-- Your main content -->

    </LinearLayout>

    <!-- The navigation drawer -->
    <com.example.app.util.ScrimInsetsFrameLayout 
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/scrimInsetsFrameLayout"
        android:layout_width="320dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@color/white"
        android:elevation="10dp"
        android:fitsSystemWindows="true"
        app:insetForeground="#4000">

        <!-- Your drawer content -->

    </com.example.app.util.ScrimInsetsFrameLayout>

</android.support.v4.widget.DrawerLayout>

Wewnątrz metody onCreate swojej aktywności ustaw kolor tła paska stanu na układzie szuflady.

MainActivity.java

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

    // ...

    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
    mDrawerLayout.setStatusBarBackgroundColor(
        getResources().getColor(R.color.primary_dark));
}

Na koniec zaktualizuj motyw aplikacji, tak aby DrawerLayoutznajdował się za paskiem stanu.

wartości-v21 / styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>

Wynik:

Suyash
źródło
10
To działało dla mnie najlepiej. Spędziłem 2 dni, żeby to zadziałało i to jest to. To powinno być oznaczone jako odpowiedź. Dziękuję bardzo.
kalehv
2
Nie używam appcompat i to nie działało. :( Czy istnieje jakikolwiek przewodnik, który działa bez appcompat?
Jared Rummler
3
To jest najdoskonalsza odpowiedź. Zaimplementowałem i przetestowałem go na różnych urządzeniach z Androidem od 4.X do 5.X i mogę potwierdzić, że działa idealnie. Wielkie dzięki.
Aritra Roy
2
Jak powiedziałem, działa idealnie, ale mam mały problem. Aktywność w Szufladzie nawigacji ma przezroczysty pasek stanu, ale wszystkie inne działania utraciły kolor „primaryDark” z paska stanu. Jak to odzyskać?
Aritra Roy
5
Trzy dni zajęło mi zaakceptowanie faktu, że obecnie nie ma innego wyjścia niż użycie tego dodatkowego układu owiniętego wokół fragmentu szuflady. W przeciwnym razie pasek stanu będzie szary (kolor tła pierwszego dziecka) lub szuflada zostanie wyświetlona poniżej paska stanu.
Denis Loh,
96

Wraz z wydaniem najnowszej Biblioteki pomocy technicznej dla systemu Android (wersja 22.2.0) mamy bibliotekę Design Design Library, aw ramach tego nowego widoku o nazwie NavigationView . Zamiast więc robić wszystko na własną rękę z ScrimInsetsFrameLayoutinnymi rzeczami, po prostu używamy tego widoku i wszystko jest zrobione za nas.

Przykład

Krok 1

Dodaj Design Support Librarydo swojego build.gradlepliku

dependencies {
    // Other dependencies like appcompat
    compile 'com.android.support:design:22.2.0'
}

Krok 2

Dodaj NavigationViewdo DrawerLayout:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/drawer_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:fitsSystemWindows="true"> <!-- this is important -->

     <!-- Your contents -->

     <android.support.design.widget.NavigationView
         android:id="@+id/navigation"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:layout_gravity="start"
         app:menu="@menu/navigation_items" /> <!-- The items to display -->
 </android.support.v4.widget.DrawerLayout>

Krok 3

Utwórz nowy zasób menu /res/menui dodaj elementy i ikony, które chcesz wyświetlić:

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_home"
            android:icon="@drawable/ic_action_home"
            android:title="Home" />
        <item
            android:id="@+id/nav_example_item_1"
            android:icon="@drawable/ic_action_dashboard"
            android:title="Example Item #1" />
    </group>

    <item android:title="Sub items">
        <menu>
            <item
                android:id="@+id/nav_example_sub_item_1"
                android:title="Example Sub Item #1" />
        </menu>
    </item>

</menu>

Krok 4

Zainicjuj NavigationView i obsługuj zdarzenia kliknięcia:

public class MainActivity extends AppCompatActivity {

    NavigationView mNavigationView;
    DrawerLayout mDrawerLayout;

    // Other stuff

    private void init() {
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
        mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem menuItem) {
                mDrawerLayout.closeDrawers();
                menuItem.setChecked(true);
                switch (menuItem.getItemId()) {
                    case R.id.nav_home:
                        // TODO - Do something
                        break;
                    // TODO - Handle other items
                }
                return true;
            }
        });
    }
}

Krok 5

Należy ustawić android:windowDrawsSystemBarBackgroundsi android:statusBarColorw values-v21przeciwnym razie szuflady won `t być wyświetlane„pod”StatusBar

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Other attributes like colorPrimary, colorAccent etc. -->
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>

Krok opcjonalny

Dodaj nagłówek do NavigationView. W tym celu po prostu utwórz nowy układ i dodaj app:headerLayout="@layout/my_header_layout"do NavigationView.

Wynik

obraz przedstawiający widok nawigacji

Notatki

  • Zaznaczony koloru wykorzystuje barwę zdefiniowaną przez colorPrimaryatrybut
  • Elementy listy używają koloru zdefiniowanego za pomocą textColorPrimaryatrybutu
  • W ikony użyć barwę zdefiniowaną przez textColorSecondaryatrybut

Możesz także sprawdzić przykładową aplikację autorstwa Chrisa Banesa, która wyróżnia NavigationView wraz z innymi nowymi widokami, które są częścią Biblioteki wsparcia projektowania (np. FloatingActionButton , TextInputLayout , Snackbar , TabLayout itp.)

odwrócić
źródło
1
dzięki @reVerse !!. > Jeśli chcesz zaktualizować każdy element i ikonę na liście z plików stylów, możesz to zrobić za pomocą:<item name="itemTextColor">@color/YOUR_COLOR</item> <item name="itemIconTint">@color/YOUR_COLOR</item>
Juan Saravia
Jak zmienić kolor tła wybranego elementu?
Joop
2
Podejście to nadal generuje NavigationView, który znajduje się za ActionBar.
southerton
1
@southerton oczywiście, musisz użyć Toolbar- nie da się tego zrobić zActionBar
reVerse
1
@ reegan29 Wystarczy zadzwonić, mDrawerLayout.openDrawer(GravityCompat.START);gdziekolwiek chcesz. Jeśli używasz, ActionBarDrawerTogglenależy to zrobić automatycznie, jak tylko klikniesz ikonę hamburgera.
powtórka
6

Spraw, by działało, w stylach value-v21 lub formacie xml należy użyć tego atrybutu:

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

To czyni magię!

Nicolas Jafelle
źródło
3
To sprawia, że ​​mój pasek akcji pojawia się również za paskiem stanu.
Michiel
Ale taki efekt staramy się osiągnąć, spójrz na aplikację Gmail 5.0? Pokazuje pasek boczny za paskiem stanu.
Nicolas Jafelle,
Nie to chciałem powiedzieć. Chociaż szuflada nawigacji znajduje się za paskiem stanu z tym wierszem kodu, podobnie pasek narzędzi / pasek akcji.
Michiel
2
Plakat i odpowiadający to pracownik Google, który zaprojektował AppCompat, więc jestem pewien, że wiedział, co robił, kiedy pisał treść.
afollestad
@Mixx, możesz ustawić Androida: fitsSystemWindows = "true" dla twojego normalnego widoku treści (jeśli wziąć przykładowo zaakceptowany układ odpowiedzi). Może działać, nawet dla Androida 4.4. Ale jest tutaj niewielka różnica: w Androidzie 5.0 poziom przezroczystości na pasku stanu jest nieco wyższy (wyższa wartość alfa) niż w Gmailu, przez co pasek stanu jest jeszcze ciemniejszy.
Qianqian
6

Wszystkie powyższe podejścia są prawidłowe i mogą działać. Utworzyłem działającą wersję demo, postępując zgodnie z powyższym przewodnikiem i przetestowałem na wersji 2.x do 5.x

Możesz sklonować z Github

Ważną rzeczą do zabawy jest aktywność główna

toolbar = (Toolbar) findViewById(R.id.toolbar);
res = this.getResources();

this.setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
    ScrimInsetsFrameLayout scrimInsetsFrameLayout = (ScrimInsetsFrameLayout)
            findViewById(R.id.linearLayout);
    scrimInsetsFrameLayout.setOnInsetsCallback(this);
} 

i oddzwonienie

@Override
public void onInsetsChanged(Rect insets) {
    Toolbar toolbar = this.toolbar;
    ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
        toolbar.getLayoutParams();
    lp.topMargin = insets.top;
    int top = insets.top;
    insets.top += toolbar.getHeight();
    toolbar.setLayoutParams(lp);
    insets.top = top; // revert
}

Absolutnie temat dla V21 działa magicznie

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- API 21 theme customizations can go here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/accent_material_light</item>
    <item name="windowActionModeOverlay">true</item>
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:windowTranslucentStatus">true</item>
</style>

i ScrimInsetsFrameLayout

Teraz jest to łatwiejsze dzięki nowej bibliotece Design Support

compile 'com.android.support:design:22.2.0'

klon z @Chris Banes https://github.com/chrisbanes/cheesesquare

Vipin Sahu
źródło
4

Wszystkie wymienione tutaj odpowiedzi są zbyt stare i długie. Najlepsze i krótkie rozwiązanie, które działa z najnowszym widokiem 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);

    }
}

spowoduje to zmianę koloru paska stanu na przezroczysty po otwarciu szuflady

Teraz, kiedy zamkniesz szufladę, musisz ponownie zmienić kolor paska stanu na ciemny, więc możesz to zrobić w ten sposób.

        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 jedną linię tj

            android:fitsSystemWindows="true"

a Twój układ szuflady 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">

i będzie wyglądał widok nawigacji

    <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 działa w pełni. Mam nadzieję, że to komuś pomaga. To może nie być najlepsze podejście, ale działa płynnie i jest łatwe do wdrożenia. Zaznacz, jeśli to pomoże. Szczęśliwe kodowanie :)

Harry Sharma
źródło
Alternatywnie, jeśli używasz widoku niestandardowego w ActionBar, możesz ustawić widoczność widoku niestandardowego na NIEWIDOCZNY w onDrawerSlide () i NA WIDOCZNY w onDrawerClosed ().
Milan,
3

Korzystam z biblioteki wsparcia projektowania. I właśnie za pomocą niestandardowego motywu uzyskałem przezroczysty pasek stanu po otwarciu szuflady nawigacji.

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

<style name="NavigationStyle" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/primaryColor</item>
    <item name="colorPrimaryDark">@color/primaryColorDark</item>

    <!-- To Make Navigation Drawer Fill Status Bar and become Transparent Too -->
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>

</style>

Na koniec dodaj motyw w pliku manifestu

<activity
  ........
  ........
 android:theme="@style/NavigationStyle"> 
</activity>

Nie zapomnij użyć właściwości android:fitsSystemWindows="true"w „DrawerLayout”

katwal-Dipak
źródło
1
jak korzystać z tego dla urządzeń interfejsu API poziomu 19?
AndroidGuy,
2

To jest najprostsze i działało dla mnie:

W wartościach-21:

<resources>
    <style name="AppTheme" parent="AppTheme.Base">
        ...
        <item name="android:windowTranslucentStatus">true</item>
    </style>
    <dimen name="topMargin">25dp</dimen>
</resources>

W wartościach:

<resources>
    <dimen name="topMargin">0dp</dimen>
</resources>

I ustaw na pasku narzędzi

android:layout_marginTop="@dimen/topMargin"
Nicolás López
źródło
Zrobiłem to i działało to jak urok na Lollipop. Ale użyłem 24dpgórnej marży.
Rafa,
Kiedy dzielisz ekran na urządzenia z Androidem 7.1, możesz zobaczyć tę lukę u góry, jeśli aplikacja jest drugą częścią ekranu.
Cícero Moura
1

Zamiast używać ScrimInsetsFrameLayout... Czy nie jest łatwiej po prostu dodać widok o stałej wysokości 24dpi tle primaryColor?

Rozumiem, że wymaga to dodania fałszywego widoku w hierarchii, ale wydaje mi się, że jest czystszy.

Już próbowałem i działa dobrze.

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!-- THIS IS THE VIEW I'M TALKING ABOUT... -->
        <View
            android:layout_width="match_parent"
            android:layout_height="24dp"
            android:background="?attr/colorPrimary" />

        <android.support.v7.widget.Toolbar
            android:id="@+id/activity_base_toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:elevation="2dp"
            android:theme="@style/ThemeOverlay.AppCompat.Dark" />

        <FrameLayout
            android:id="@+id/activity_base_content_frame_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>

    <fragment
        android:id="@+id/activity_base_drawer_fragment"
        android:name="com.myapp.drawer.ui.DrawerFragment"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:elevation="4dp"
        tools:layout="@layout/fragment_drawer" />

</android.support.v4.widget.DrawerLayout>
mato
źródło
Kiedy dzielisz ekran na urządzenia z Androidem 7.1, możesz zobaczyć tę lukę u góry, jeśli aplikacja jest drugą częścią ekranu.
Cícero Moura
0

Spróbuj tego:

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


<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--Main layout and ads-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <FrameLayout
            android:id="@+id/ll_main_hero"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">

        </FrameLayout>

        <FrameLayout
            android:id="@+id/ll_ads"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <View
                android:layout_width="320dp"
                android:layout_height="50dp"
                android:layout_gravity="center"
                android:background="#ff00ff" />
        </FrameLayout>


    </LinearLayout>

    <!--Toolbar-->
    <android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/toolbar"
        android:elevation="4dp" />
</FrameLayout>


<!--left-->
<ListView
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:divider="@null"
    android:background="@mipmap/layer_image"
    android:id="@+id/left_drawer"></ListView>

<!--right-->
<FrameLayout
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="right"
    android:background="@mipmap/layer_image">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/ken2"
        android:scaleType="centerCrop" />
</FrameLayout>

styl:

<style name="ts_theme_overlay" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/red_A700</item>
    <item name="colorPrimaryDark">@color/red1</item>
    <item name="android:windowBackground">@color/blue_A400</item>
</style>

Główne działanie rozszerza ActionBarActivity

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

Teraz możesz onCreateOptionsMenupolubić jak zwykle ActionBar z ToolBar.

To jest mój układ

  • GÓRA: Lewa szuflada - prawa szuflada
    • MID: ToolBar (ActionBar)
    • DOLNY: ListFragment

Mam nadzieję, że rozumiesz! Baw się dobrze!

Son Nguyen Thanh
źródło