Panel Samping Navigasi semi-transparan di atas bilah status tidak berfungsi

86

Saya sedang mengerjakan proyek Android dan saya mengimplementasikan Navigation Drawer. Saya membaca Spesifikasi Desain Material baru dan Daftar Periksa Desain Material .
Spesifikasi mengatakan bahwa panel geser keluar harus mengapung di atas segalanya termasuk bilah status dan semi-transparan di atas bilah status.

Panel navigasi saya berada di atas bilah status tetapi tidak ada transparansi apa pun. Saya telah mengikuti kode dari ini posting SO seperti yang disarankan di tempat blog pengembang Google, tautan di atas Bagaimana cara menggunakan DrawerLayout untuk ditampilkan di atas ActionBar / Toolbar dan di bawah bilah status? .

Di bawah ini adalah tata letak XML saya

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

Di bawah ini adalah tema aplikasi saya

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

Di bawah ini adalah tema apps v21 saya

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

Di bawah ini adalah metode onCreate saya

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

Di bawah ini adalah tangkapan layar dari panel samping navigasi saya yang menunjukkan bahwa bagian atas tidak semi transparan

Tangkapan layar menunjukkan tidak transparan di atas bilah status

Boardy
sumber
Posting tangkapan layar dari hasil Anda.
Alok Nair
@ Boardy apakah Anda berhasil membuatnya bekerja?
Michele La Ferla
Tak dapat menyetel efek Transparan di bilah status. Singkirkan itu.
Ronak Gadhia

Jawaban:

103

Latar belakang bilah status Anda berwarna putih, latar belakang laci Anda LinearLayout. Mengapa? Anda adalah pengaturan fitsSystemWindows="true"untuk Anda DrawerLayoutdan bagian LinearLayoutdalamnya. Ini menyebabkan Anda LinearLayoutmeluas di belakang bilah status (yang transparan). Dengan demikian, membuat latar belakang untuk bagian laci bilah status berwarna putih.

masukkan deskripsi gambar di sini
Jika Anda tidak ingin laci Anda diperpanjang di belakang bilah status (ingin memiliki latar belakang semi-transparan untuk seluruh bilah status), Anda dapat melakukan dua hal:

1) Anda cukup menghapus nilai latar belakang apa pun dari Anda LinearLayoutdan mewarnai latar belakang konten Anda di dalamnya. Atau

2) Anda dapat menghapus fitsSystemWindows="true"file LinearLayout. Saya pikir ini adalah pendekatan yang lebih logis dan lebih bersih. Anda juga akan menghindari bayangan yang dilemparkan di bawah bilah status, di mana laci navigasi Anda tidak meluas.

masukkan deskripsi gambar di sini
Jika Anda ingin laci Anda diperpanjang di belakang bilah status dan memiliki hamparan semi-transparan berukuran bilah status, Anda dapat menggunakan a ScrimInsetFrameLayoutsebagai wadah untuk konten laci Anda ( ListView) dan menyetel latar belakang bilah status menggunakan app:insetForeground="#4000". Tentu saja, Anda dapat mengubah #4000apa pun yang Anda inginkan. Jangan lupa simpan fitsSystemWindows="true"disini!

Atau jika Anda tidak ingin menampilkan konten Anda dan hanya menampilkan warna solid, Anda dapat mengatur latar belakang Anda LinearLayoutsesuai keinginan. Jangan lupa untuk mengatur latar belakang konten Anda secara terpisah!

EDIT: Anda tidak perlu lagi berurusan dengan semua ini. Silakan lihat Design Support Library untuk mengetahui penerapan Navigasi Drawer / View yang lebih mudah.

xip
sumber
Terima kasih atas bantuan Anda. Maaf atas keterlambatan untuk kembali, sangat sibuk. Saya telah menyiapkan hadiah lain untuk memberi penghargaan atas jawaban Anda seperti yang saya siapkan sebelumnya tetapi selesai sebelum saya punya waktu untuk menerapkan saran Anda. Sayangnya saya harus menunggu 23 jam jadi saya akan menambahkannya secepat mungkin
Boardy
Peringatan! Dengan opsi 1 atau 2, pastikan untuk mengawasi overdraw Anda (Anda dapat memeriksanya di opsi dev di pengaturan telepon). Ketika saya hanya mengatur latar belakang konten di dalam semua yang ada di belakang laci juga digambar. Jika tidak, jawaban yang bagus, pasti menghemat waktu saya :)
Daiwik Daarun
1
Bisakah Anda menjelaskan solusi apa yang kami perlukan untuk menggunakan pustaka dukungan desain? Saya mengalami beberapa masalah, bahkan dengan jawaban yang diposting Chris Banes.
mDroidd
29

Yang perlu Anda lakukan adalah menggunakan beberapa warna semi-transparan untuk bilah status. Tambahkan baris ini ke tema v21 Anda:

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

Jangan lupa bahwa color(resource) harus selalu dalam format #AARRGGBB. Artinya warna tersebut juga akan menyertakan nilai alpha.

mroczis.dll
sumber
Anda orangnya, tapi ... Bisakah Anda memberi tahu saya mengapa ini hanya berfungsi di Aktivitas yang memiliki Laci? Yang lainnya, mereka yang belum, mereka menunjukkan bilah Status abu-abu.
Joaquin Iurchuk
15

Mengapa tidak menggunakan sesuatu yang mirip dengan ini?

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

Kode di atas menggunakan sumber daya alfa android:backgrounduntuk dapat menampilkan transparansi dalam bilah tindakan.

Ada cara lain untuk melakukan ini melalui kode, seperti yang ditunjukkan oleh jawaban lain. Jawaban saya di atas, apakah perlu file layout xml yang menurut saya mudah diedit.

Michele La Ferla
sumber
4
Mengapa tidak, tetapi tidak jelas apa yang Anda ubah dan bagaimana ini menjawab pertanyaan tersebut.
rds
atur pembatas menjadi kode alpha transparan dan digunakan di warna latar belakang
Michele La Ferla
9

Semua jawaban yang disebutkan di sini terlalu tua dan panjang. Solusi terbaik dan singkat yang bekerja dengan Navigationview terbaru adalah

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

    }
}

ini akan mengubah warna bilah status Anda menjadi transparan saat Anda membuka laci

Sekarang ketika Anda menutup laci Anda perlu mengubah warna bilah status lagi menjadi gelap. Jadi Anda bisa melakukannya dengan cara ini.

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

dan kemudian di tata letak utama tambahkan satu baris yaitu

            android:fitsSystemWindows="true"

dan tata letak laci Anda akan terlihat seperti ini

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

dan tampilan navigasi Anda akan terlihat

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

Saya telah mengujinya dan berfungsi penuh, semoga dapat membantu seseorang. Ini mungkin bukan pendekatan terbaik tetapi berfungsi dengan lancar dan mudah diterapkan. Tandai jika membantu. Selamat membuat kode :)

Harry Sharma
sumber
Terima kasih! Ini menghemat banyak waktu saya. Ini bekerja sempurna dengan NavigationView terbaru. Bagi siapa pun yang tidak dapat membuat ini berfungsi, pastikan Anda memilih warna dengan beberapa transparansi untuk "colorPrimaryDarktrans", jika tidak, Anda tidak dapat melihat perubahan sama sekali.
Rui
Bekerja dengan sempurna, satu-satunya kelemahan adalah bilah status 'berkedip' saat onDrawerClosed dipanggil tetapi jika Anda menyetel warna transparan colorPrimaryDarktrans ke # 05000000, hampir tidak terlihat
Kirill Karmazin
8

Anda perlu membungkus tata letak panel navigasi di dalam file ScrimLayout.

A ScrimLayoutpada dasarnya menggambar persegi panjang semi transparan di atas tata letak laci navigasi Anda. Untuk mengambil ukuran inset, cukup timpa fitSystemWindowsdi file ScrimLayout.

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

Kemudian timpa onDrawuntuk menggambar persegi panjang semi transparan.

Sebuah contoh implementasi dapat ditemukan dalam sumber Google IO App. Di sini Anda dapat melihat bagaimana itu digunakan dalam layout xml.

Markus Hai
sumber
5

Jika Anda ingin panel navigasi berada di atas bilah status dan semi-transparan di atas bilah status. Sumber Aplikasi Android Google I / O memberikan solusi yang baik ( APK di Play Store tidak diperbarui ke versi terakhir)

Pertama, Anda membutuhkan 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);
    }
}

Kemudian, dalam layout XML Anda, ubah bagian ini

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

Ubah LinearLayout menjadi ScrimInsetFrameLayout Anda seperti ini

<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>
skyfishjy.dll
sumber
HI, terima kasih atas jawabannya .. Saya tidak dapat menemukannya, dari mana kami mendapatkan OnInsetsCallback ... Terima kasih sebelumnya.
Ashokchakravarthi Nagarajan
dapatkah Anda meletakkan ScrimInsetsView_insetForegroundatributnya.
reegan29
1
Gunakan android.support.design.internal.ScrimInsetsFrameLayoutdari pustaka dukungan
Roman
3

Saya memiliki fitur serupa untuk diterapkan dalam proyek saya. Dan untuk membuat laci saya transparan, saya hanya menggunakan transparansi untuk warna hex . Menggunakan 6 digit hex, Anda memiliki 2 digit hex untuk setiap nilai merah, hijau dan biru. tetapi jika Anda memasukkan dua digit tambahan (8 digit hex), maka Anda memiliki ARGB (dua digit untuk nilai alpha) ( Lihat di sini ).

Berikut adalah Hex Opacity Values: untuk 2 digit tambahan

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

Sebagai contoh: jika Anda memiliki warna de hex (# 111111) cukup masukkan salah satu nilai opacity untuk mendapatkan transparansi. seperti ini: (# 11111100)

Laci saya tidak menutupi panel tindakan (seperti milik Anda) tetapi transparansi dapat diterapkan dalam kasus ini juga. Ini kode saya:

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

Dan berikut adalah artikel lain yang dapat membantu Anda memahami kode alfa dalam warna hex.

fdsilva.dll
sumber
1

Solusi yang ada sudah cukup usang. Inilah solusi terbaru yang seharusnya berfungsi dengan sempurna di AndroidX atau pustaka Material.

  • Tambahkan android:fitsSystemWindows="true"ke tampilan root dari layout Anda, yang merupakan DrawerLayout untuk kasus Anda.

    Ini memberitahu View untuk menggunakan seluruh layar untuk mengukur & tata letak, tumpang tindih dengan status bar.

  • Tambahkan berikut ini ke gaya XML Anda

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

    windowTranslucentStatusakan membuat bilah status transparan
    windowDrawsSystemBarBackgroundsmemberi tahu bilah status untuk menggambar apa pun di bawahnya alih-alih menjadi kehampaan hitam.

  • Panggilan DrawerLayout.setStatusBarBackground()atau DrawerLayout.setStatusBarBackgroundColor()dalam Aktivitas utama Anda

    Ini memberitahu DrawerLayout untuk mewarnai area status bar.

Brown Smith
sumber
0

Semua jawaban di sini sangat rumit, izinkan saya memberi Anda kode sederhana langsung. Di bawah gaya AppTheme Anda, tambahkan baris kode ini dan Anda akan mendapatkan bilah status semi transparan abu-abu saat Anda membuka laci.

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

ini akan membuatnya berhasil.

Keshav Bhamaan
sumber
-1

Di atas solusi bagus, tetapi tidak berhasil dalam kasus saya,

kasus saya: bilah status memiliki set warna kuning sudah menggunakan gaya, tidak tembus cahaya. dan warna panel navigasi saya putih, sekarang setiap kali saya menggambar panel samping navigasi saya, ia selalu berada di belakang bilah status dan bilah navigasi juga, karena warna bilah navigasi juga disetel.

tujuan: untuk mengubah bilah status dan warna bilah navigasi saat panel samping navigasi dibuka dan mengembalikannya saat ditutup.

solusi:

        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) {
        }
    });
Abhishek Garg
sumber