ฉันจะใช้ DrawerLayout เพื่อแสดงเหนือแถบเครื่องมือ / แถบเครื่องมือและใต้แถบสถานะได้อย่างไร


394

ฉันเคยเห็นในการออกแบบวัสดุใหม่Side Spec สเป็คที่คุณสามารถแสดงลิ้นชักบนแถบการกระทำและด้านหลังแถบสถานะ ฉันจะใช้สิ่งนี้ได้อย่างไร


4
แม้กระทั่งทุกวันนี้ยังไม่มีคำตอบที่ชัดเจนที่ทำงานได้กับความเข้ากันได้แบบย้อนหลัง ปัญหาประเภทนี้ทำให้โปรแกรมเมอร์โกรธมากจริงๆ ส่งเสริม API "N" และแง่มุมต่างๆมากมายเพื่อปรับปรุงในระบบ Android
Val Martinez

คำตอบ:


528

ฟังก์ชั่นใหม่ในเฟรมเวิร์กและ libs สนับสนุนให้ตรง มีสามส่วนของจิ๊กซอว์:

  1. ใช้แถบเครื่องมือเพื่อให้คุณสามารถฝังแถบการกระทำลงในลำดับชั้นการดู
  2. ทำDrawerLayout fitsSystemWindowsเพื่อวางเลย์เอาต์ไว้ด้านหลังแถบระบบ
  3. ปิดใช้งานการTheme.Materialระบายสีแถบสถานะปกติเพื่อให้ DrawerLayout สามารถวาดได้ที่นั่นแทน

ฉันจะสมมติว่าคุณจะใช้แอปคอมพ์ใหม่

ขั้นแรกเค้าโครงของคุณควรมีลักษณะดังนี้:

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

จากนั้นในกิจกรรม / ส่วนของคุณ:

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

จากนั้นคุณต้องตรวจสอบให้แน่ใจว่า DrawerLayout ปรากฏอยู่ด้านหลังแถบสถานะ คุณทำเช่นนั้นโดยเปลี่ยนธีม values-v21 ของคุณ:

ค่า-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>

หมายเหตุ: หากมีการ<fragment android:name="fragments.NavigationDrawerFragment">ใช้งานแทน

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

    <!-- Your drawer content -->

</LinearLayout>

เลย์เอาต์ที่เกิดขึ้นจริงผลที่ต้องการจะประสบความสำเร็จถ้าคุณโทรfitsSystemWindows(boolean)ในมุมมองที่คุณกลับมาจากonCreateViewวิธีการ

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

3
ใช่DrawerLayoutจำเป็นต้องจัดวางไว้ด้านหลังแถบระบบ จากนั้นคุณต้องตั้งค่าไว้ในมุมมองลิ้นชักเพื่อให้DrawerLayoutวางไว้ภายในส่วนแทรกของหน้าต่าง
Chris Banes

11
ไม่สามารถใช้งานได้เลย ด้วยโค้ดด้านบนในแอปพลิเคชันสาธิตใหม่ผลลัพธ์จะคล้ายกับที่ @ScootrNova อธิบาย ดูภาพหน้าจอนี้: imgur.com/QLk3syt
Michael Schmidt

6
ดูเหมือนว่าคุณจะต้องใช้ค่าลบlayout_marginTopในรูทของโครงร่างของเนื้อหาลิ้นชัก ไม่เช่นนั้นพื้นหลังของเค้าโครงเนื้อหาของลิ้นชักของคุณจะถูกวาดที่ด้านบนของแถบสถานะและทุกอย่างจะถูกเลื่อนลงมา นี้ดูเหมือนว่าเป็นวิธีการแก้ปัญหาขั้นต้นเท่าที่ฉันรู้ว่าไม่มี? attr / statusBarSize หรืออะไรทำนองนั้นที่จัดทำโดย Android
Charles Madere

26
เพื่อให้ได้เอฟเฟ็กต์ที่ลิ้นชักมองเห็นได้ผ่านแถบสถานะฉันจึงสิ้นสุดการตั้งค่า android: FitsSystemWindows เป็น false บน drawerLayout, android: fitsSystemWindows เป็น true บนโครงร่างเนื้อหาหลักของฉัน (เลย์เอาต์ประกอบด้วย Toolbar) และเพิ่ม <item item = "android: windowTranslucentStatus"> true </item> สำหรับชุดรูปแบบของฉัน - บน Lollipop นั่นคือ
Jakob

8
คำตอบนี้ไม่สมบูรณ์ นอกจากนี้คุณยังต้องห่อลิ้นชักนำทางของคุณไว้ใน ScrimLayout ดูstackoverflow.com/a/26926998/174149
Markus Hi

138

แก้ไข: ห้องสมุดสนับสนุนการออกแบบใหม่รองรับสิ่งนี้และไม่จำเป็นต้องใช้วิธีการก่อนหน้านี้อีกต่อไป

ตอนนี้สามารถทำได้โดยใช้ใหม่ห้องสมุดการสนับสนุนการออกแบบ Android

คุณสามารถดูแอปตัวอย่างของ Cheesesquareโดย Chris Banes ซึ่งสาธิตคุณลักษณะใหม่ทั้งหมด


วิธีก่อนหน้า:

เนื่องจากไม่มีวิธีการแก้ปัญหาที่สมบูรณ์โพสต์นี่คือวิธีที่ฉันได้ผลลัพธ์ที่ต้องการ

ก่อนอื่นให้รวมScrimInsetsFrameLayoutในโครงการของคุณ

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

จากนั้นสร้างสไตล์เพื่อให้insetForegroundสามารถตั้งค่า

ค่า / attrs.xml

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

อัพเดทไฟล์ xml กิจกรรมของคุณและให้แน่ใจว่าandroid:fitsSystemWindowsมีการตั้งค่าให้เป็นจริงทั้งสองเช่นเดียวกับDrawerLayoutScrimInsetsFrameLayout

รูปแบบ / 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>

ภายในเมธอด onCreate ของกิจกรรมของคุณตั้งค่าสีพื้นหลังของแถบสถานะบนโครงร่างลิ้นชัก

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

ในที่สุดก็อัพเดตธีมของแอพของคุณเพื่อที่DrawerLayoutจะอยู่ด้านหลังแถบสถานะ

ค่า-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>

ผลลัพธ์:


10
สิ่งนี้ทำงานได้ดีที่สุดสำหรับฉัน ฉันใช้เวลา 2 วันในการทำงานสิ่งนี้และนี่คือหนึ่ง ควรทำเครื่องหมายเป็นคำตอบ ขอบคุณมาก.
kalehv

2
ฉันไม่ได้ใช้แอปคอมแพคและไม่ได้ผล :( มีหนึ่งคำแนะนำใด ๆ ที่ได้รับการทำงานนี้โดยไม่ AppCompat?
Jared Rummler

3
นี่คือคำตอบที่สมบูรณ์แบบที่สุด ฉันได้ติดตั้งและทดสอบกับอุปกรณ์ Android ต่าง ๆ ตั้งแต่ 4.X ถึง 5.X และสามารถยืนยันได้ว่ามันทำงานได้อย่างสมบูรณ์แบบ ขอบคุณมาก.
Aritra Roy

2
อย่างที่ฉันพูดมันใช้งานได้ดี แต่ฉันมีปัญหาเล็กน้อย กิจกรรมที่มีการนำทางลิ้นชักมีแถบสถานะโปร่งใส แต่กิจกรรมอื่น ๆ ทั้งหมดได้สูญเสียสี "primaryDark" จากแถบสถานะ จะได้รับกลับมาได้อย่างไร
Aritra Roy

5
ฉันใช้เวลาสามวันเพื่อยอมรับว่าขณะนี้ไม่มีวิธีอื่นนอกจากการใช้เลย์เอาต์เพิ่มเติมนี้ที่พันไว้รอบ ๆ ส่วนลิ้นชัก มิฉะนั้นแถบสถานะจะเป็นสีเทา (สีพื้นหลังของเด็กคนแรก) หรือลิ้นชักจะปรากฏใต้แถบสถานะ
เดนิสโลห์

96

ด้วยการเปิดตัวล่าสุดAndroid สนับสนุนห้องสมุด (รอบ 22.2.0)เรามีห้องสมุดการสนับสนุนการออกแบบและเป็นส่วนหนึ่งของเรื่องนี้ในมุมมองใหม่ที่เรียกว่าNavigationView ดังนั้นแทนที่จะทำทุกอย่างด้วยตัวเราเองด้วยScrimInsetsFrameLayoutและสิ่งอื่น ๆ ทั้งหมดเราเพียงแค่ใช้มุมมองนี้และทุกอย่างก็ทำเพื่อเรา

ตัวอย่าง

ขั้นตอนที่ 1

เพิ่มลงDesign Support Libraryในbuild.gradleไฟล์ของคุณ

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

ขั้นตอนที่ 2

เพิ่มในNavigationViewของคุณ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>

ขั้นตอนที่ 3

สร้างเมนูทรัพยากรใหม่/res/menuและเพิ่มรายการและไอคอนที่คุณต้องการแสดง:

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

ขั้นตอนที่ 4

เริ่ม NavigationView และจัดการเหตุการณ์คลิก:

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

ขั้นตอนที่ 5

ให้แน่ใจว่าชุดandroid:windowDrawsSystemBarBackgroundsและandroid:statusBarColorในvalues-v21มิฉะนั้นลิ้นชักของคุณได้รับรางวัล `จะแสดง "ภายใต้หมวด" แถบสถานะ

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

ขั้นตอนเพิ่มเติม

เพิ่มส่วนหัวใน NavigationView เพียงแค่สร้างเลย์เอาต์ใหม่และเพิ่มapp:headerLayout="@layout/my_header_layout"ไปยัง NavigationView

ผลลัพธ์

รูปภาพแสดงมุมมองการนำทาง

หมายเหตุ

  • สีไฮไลต์ใช้สีที่กำหนดผ่านcolorPrimaryแอตทริบิวต์
  • บัตรรายการใช้สีที่กำหนดไว้ผ่านทางtextColorPrimaryแอตทริบิวต์
  • ไอคอนใช้สีที่กำหนดไว้ผ่านทางtextColorSecondaryแอตทริบิวต์

คุณสามารถตรวจสอบตัวอย่างแอพโดยChris Banesซึ่งเน้น NavigationView พร้อมกับมุมมองใหม่อื่น ๆ ที่เป็นส่วนหนึ่งของ Library Support Design (เช่นFloatingActionButton , TextInputLayout , Snackbar , TabLayoutเป็นต้น)


1
ขอบคุณ @reVerse !! > หากคุณต้องการอัปเดตทุกรายการและไอคอนในรายการจากไฟล์สไตล์คุณสามารถทำได้โดยใช้:<item name="itemTextColor">@color/YOUR_COLOR</item> <item name="itemIconTint">@color/YOUR_COLOR</item>
Juan Saravia

คุณจะเปลี่ยนสีพื้นหลังของรายการที่เลือกได้อย่างไร
Joop

2
วิธีการนี้ยังคงสร้าง NavigationView ที่อยู่เบื้องหลัง ActionBar
ชาวใต้

1
@ แน่นอนว่าคุณต้องใช้ a Toolbar- ไม่มีทางทำเช่นนี้กับActionBar
ย้อนกลับ

1
@ reegan29 เพียงแค่โทรไปmDrawerLayout.openDrawer(GravityCompat.START);ทุกที่ที่คุณต้องการ หากคุณใช้งานActionBarDrawerToggleสิ่งนี้ควรทำโดยอัตโนมัติทันทีที่คุณคลิกที่ไอคอนแฮมเบอร์เกอร์
ย้อนกลับ

6

ทำให้เป็นจริงในสไตล์ -V21 หรือธีม xml จำเป็นต้องใช้คุณลักษณะนี้:

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

นั่นทำให้เวทมนต์!


3
สิ่งนี้ทำให้แถบแอ็คชั่นของฉันปรากฏหลังแถบสถานะเช่นกัน
Michiel

แต่นั่นคือเอฟเฟกต์ที่เราพยายามทำให้ดูที่แอป Gmail 5.0 มันแสดงแถบด้านหลังแถบสถานะ
Nicolas Jafelle

นั่นไม่ใช่สิ่งที่ฉันตั้งใจจะพูด แม้ว่าลิ้นชักการนำทางอยู่ด้านหลังแถบสถานะด้วยรหัสบรรทัดนี้ดังนั้นแถบเครื่องมือ / แอ็คชัน
Michiel

2
ผู้โพสต์และผู้ตอบคำถามเป็นพนักงานของ Google ผู้ออกแบบ AppCompat ดังนั้นฉันค่อนข้างแน่ใจว่าเขารู้ว่าเขาทำอะไรเมื่อเขาเขียนเนื้อหา
afollestad

@Mixx, คุณสามารถตั้งค่า android: fitsSystemWindows = "true" สำหรับมุมมองเนื้อหาปกติของคุณ (ถ้าใช้รูปแบบคำตอบที่ได้รับการยอมรับ) มันสามารถทำงานได้แม้กระทั่งสำหรับ Android 4.4 แต่มีความแตกต่างเล็กน้อยที่นี่: ใน Android 5.0 ระดับความโปร่งใสบนแถบสถานะค่อนข้างสูงกว่า (ค่าอัลฟาสูงกว่า) ใน GMail ทำให้แถบสถานะนั้นเข้มขึ้น
Qianqian

6

วิธีการข้างต้นทั้งหมดถูกต้องและอาจใช้งานได้ ฉันได้สร้างตัวอย่างที่ใช้งานได้ตามคู่มือข้างต้นและทดสอบกับ 2.x ถึง 5.x

คุณสามารถโคลนจากGithub

สิ่งสำคัญในการเล่นคือในกิจกรรมหลัก

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

และโทรกลับ

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

ชุดรูปแบบสำหรับ V21 ทำให้เกิดความมหัศจรรย์

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

และ ScrimInsetsFrameLayout

ตอนนี้สิ่งนี้จะง่ายขึ้นด้วยห้องสมุดสนับสนุนการออกแบบใหม่

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

โคลนจาก @Chris Banes https://github.com/chrisbanes/cheesesquare


4

คำตอบทั้งหมดที่กล่าวถึงที่นี่เก่าเกินไปและยาวเกินไปทางออกที่ดีและสั้นที่สุดที่ใช้งานได้กับ 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);

    }
}

นี่จะเปลี่ยนสีแถบสถานะเป็นโปร่งใสเมื่อคุณเปิดลิ้นชัก

ตอนนี้เมื่อคุณปิดลิ้นชักคุณต้องเปลี่ยนสีแถบสถานะอีกครั้งเพื่อมืดดังนั้นคุณสามารถทำได้ด้วยวิธีนี้

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

ฉันได้ทดสอบและใช้งานได้อย่างเต็มที่หวังว่าจะช่วยให้ใครบางคนนี่อาจไม่ใช่วิธีที่ดีที่สุด แต่ทำงานได้อย่างราบรื่นและใช้งานง่าย ทำเครื่องหมายว่ามันช่วยได้หรือไม่แฮปปี้โค้ด :)


หรือถ้าคุณใช้มุมมองที่กำหนดเองใน ActionBar คุณสามารถตั้งค่าการมองเห็นของมุมมองที่กำหนดเองเป็น INVISIBLE ใน onDrawerSlide () และไปที่ VISIBLE ใน onDrawerClosed ()
มิลาน

3

ฉันกำลังใช้ห้องสมุดสนับสนุนการออกแบบ และเพียงแค่ใช้ชุดรูปแบบที่กำหนดเองฉันรู้สึกถึงแถบสถานะโปร่งใสเมื่อเปิดลิ้นชักนำทาง

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

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

ในที่สุดก็เพิ่มชุดรูปแบบในไฟล์รายการ

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

อย่าลืมใช้คุณสมบัติandroid:fitsSystemWindows="true"ใน "DrawerLayout"


1
วิธีการใช้สิ่งนี้สำหรับอุปกรณ์ API ระดับ 19?
AndroidGuy

2

นี่ง่ายที่สุดและใช้ได้กับฉัน:

ในค่า -21:

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

ในค่า:

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

และตั้งเป็นแถบเครื่องมือของคุณ

android:layout_marginTop="@dimen/topMargin"

ฉันก็ทำเช่นนี้และมันก็ใช้งานได้เหมือนเสน่ห์ของ Lollipop แต่ฉันใช้24dpสำหรับระยะขอบบนสุด
Rafa

เมื่อคุณแบ่งหน้าจอบนอุปกรณ์ที่มี Android 7.1 คุณจะเห็นช่องว่างนี้ด้านบนหากแอพของคุณเป็นส่วนที่สองของหน้าจอ
Cícero Moura

1

แทนที่จะใช้ScrimInsetsFrameLayout... การเพิ่มมุมมองด้วยความสูงคงที่24dpและพื้นหลังprimaryColorใช่หรือไม่

ฉันเข้าใจว่าสิ่งนี้เกี่ยวข้องกับการเพิ่มมุมมองดัมมี่ในลำดับชั้น แต่ดูเหมือนว่าฉันจะสะอาดขึ้น

ฉันลองแล้วและใช้งานได้ดี

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

เมื่อคุณแบ่งหน้าจอบนอุปกรณ์ที่มี Android 7.1 คุณจะเห็นช่องว่างนี้ด้านบนหากแอพของคุณเป็นส่วนที่สองของหน้าจอ
Cícero Moura

0

ลองกับสิ่งนี้:

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

สไตล์:

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

กิจกรรมหลักช่วยขยาย ActionBarActivity

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

ตอนนี้คุณสามารถonCreateOptionsMenuชอบแถบเครื่องมือปกติด้วยแถบเครื่องมือ

นี่คือเลย์เอาต์ของฉัน

  • TOP: ลิ้นชักด้านซ้าย - ลิ้นชักด้านขวา
    • MID: แถบเครื่องมือ (ActionBar)
    • ด้านล่าง: ListFragment

หวังว่าคุณจะเข้าใจขอให้สนุก!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.