• Android导航抽屉


    本文所有代码均位于https://github.com/MADMAX110/CatChat
    之前使用过标签页布局可以让用户在应用中轻松地导航。
    当只有为数不多地几个类别屏幕,而且它们都在应用层次结构地同一级上,标签页布局就很适用。
    抽屉导航可以实现更多选择,这是一个滑出式面板,包含了应用其他部分地链接。这可以把链接分组为不同的区段。

    一、新建一个Email应用

    在这里新建一个email应用创建一个抽屉导航,这个应用名为CatChat,这个导航抽屉将包含一个头部和一组选项,主要选项分别对应用户的收件箱,草稿箱,已发送邮件和废纸篓。这里还会为帮助和反馈选项包含一个单独的支持区段。
    要实现一个导航抽屉,需要向活动的布局增加一个抽屉布局,这会定义一个可以打开和关闭的抽屉,它需要包含两个视图:一个对应主要内容,一个对应抽屉内容。
    主要步骤:
    1、为应用的内容创建基本片段和活动。
    创建片段:IndexFragment、DraftsFragments、SentItemsFragment和TrashFragment。
    创建活动:Helpactivity、FeedbackActivity。
    2、创建抽屉的头部
    抽屉头部布局为nav_header.xml,包含一个图像和一些文本。
    3、创建抽屉的选项
    为抽屉要显示的选项建立一个菜单menu_nav.xml。
    4、创建导航抽屉
    将为应用的主活动增加这个导航抽屉,让它显示头部和选项。然后编写活动代码控制抽屉的行为。

    二、创建CatChat工程

    如图创建新工程CatChat。
    在这里插入图片描述
    在carchat包中创建一个名为InboxFragment的新片段,然后把它的布局名命名为fragment_inbox.xml。更新其中IndexFragment.java和fragment_inbox.xml的代码:

    package com.hafd.catchat;
    
    import android.os.Bundle;
    import androidx.fragment.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    public class InboxFragment extends Fragment {
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_inbox, container, false);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".InboxFragment">
    
        
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="inbox" />
    
    LinearLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    创建DraftsFragment,其布局名为fragment_drafts.xml

    package com.hafd.catchat;
    
    import android.os.Bundle;
    import androidx.fragment.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    public class DraftsFragment extends Fragment {
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_inbox, container, false);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".DraftsFragment">
    
        
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Drafts" />
    
    FrameLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    创建SentItemsFragment

    package com.hafd.catchat;
    
    import android.os.Bundle;
    import androidx.fragment.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    public class SentItemsFragment extends Fragment {
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_inbox, container, false);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".SentItemsFragment">
    
        
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Sent items" />
    
    FrameLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    创建TrashFragment

    package com.hafd.catchat;
    
    import android.os.Bundle;
    import androidx.fragment.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    public class TrashFragment extends Fragment {
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_inbox, container, false);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".TrashFragment">
    
        
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Trash" />
    
    FrameLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    三、创建一个工具条布局

    在layou文件夹中新建一个名为toolbar_main的布局。

    
    <androidx.appcompat.widget.Toolbar
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    更新AndroidManifest.xml中的 android:theme="@style/AppTheme"
    更新values文件夹中的colors.xml,增加以下三个颜色:

        <color name="colorPrimary">#3F51B5color>
        <color name="colorPrimaryDark">#303F9Fcolor>
        <color name="colorAccent">#FF4081color>
    
    • 1
    • 2
    • 3

    更新应用的主题,在values文件夹中创建一个Values resource file,将文件命名为styles。

    
    <resources>
        <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
            "colorPrimary">@color/colorPrimary
            "colorPrimaryDark">@color/colorPrimaryDark
            "colorAccent">@color/colorAccent
        style>
    resources>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    四、创建活动

    在catchat包中创建一个名为HelpActivity的活动,其布局为activity_help。

    
    <androidx.constraintlayout.widget.ConstraintLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".HelpActivity">
    
        <include
            layout="@layout/toolbar_main"
            android:id="@+id/toolbar" />
        
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Help"/>
        
    androidx.constraintlayout.widget.ConstraintLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    package com.hafd.catchat;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.widget.Toolbar;
    
    import android.os.Bundle;
    
    public class HelpActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_help);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    同理,在catchat包中创建一个名为FeedbackActivity的活动,其布局为activity_feedback

    
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".FeedbackActivity">
    
        <include
            layout="@layout/toolbar_main"
            android:id="@+id/toolbar" />
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Feedback"/>
    
    androidx.constraintlayout.widget.ConstraintLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    package com.hafd.catchat;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.widget.Toolbar;
    
    import android.os.Bundle;
    
    public class FeedbackActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_feedback);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    五、创建导航抽屉

    前面已经在工程中增加了需要的所有片段和活动,导航抽屉中的选项将连接到这些片段和活动。接下来要创建导航抽屉本身。
    导航抽屉本身将包含一个导航抽屉头部和一组选项:
    创建导航抽屉头部
    在layout文件夹中新建一个名为nav_header的布局文件,这个布局包含一个图像和两个文本视图。
    将下面一张图片增加到drawable文件夹中:
    在这里插入图片描述
    在string.xml中增加两个字符串资源:

        <string name="app_name">CatChatstring>
        <string name="user_name">spot@catchat.comstring>
    
    • 1
    • 2

    下面是完整的nav_header.xml代码

    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:theme="@style/ThemeOverlay.AppCompat.Dark">
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scaleType="centerCrop"
            android:src="@drawable/kitten_small" />
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:gravity="bottom|start"
            android:layout_margin="16dp" >
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/app_name"
                android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/user_name"/>
    
        LinearLayout>
    
    FrameLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    导航抽屉从一个菜单资源文件得到它的选项列表。响应的代码与向应用条增加一组选项的代码是类似的。在res文件夹中创建一个menu文件夹,在该文件夹中创建一个menu_nav.xml的菜单资源文件。
    需要先在string.xml中增加一些字符串资源:

        <string name="nav_inbox">Mesagezstring>
        <string name="nav_drafts">Draftzstring>
        <string name="nav_sent">Sent mesagezstring>
        <string name="nav_trash">In da trashstring>
        <string name="nav_support">Supportstring>
        <string name="nav_help">Halpstring>
        <string name="nav_feedback">Giv us feedbackstring>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    接下来就可以开始创建菜单资源文件了,按你希望的显示顺序增加选项,下面是完整的menu_nav.xml的代码。

    
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <group android:checkableBehavior="single">
            <item
                android:id="@+id/nav_inbox"
                android:icon="@android:drawable/sym_action_email"
                android:title="@string/nav_inbox"/>
            <item
                android:id="@+id/nav_drafts"
                android:icon="@android:drawable/ic_menu_edit"
                android:title="@string/nav_drafts"/>
            <item
                android:id="@+id/nav_sent"
                android:icon="@android:drawable/ic_menu_send"
                android:title="@string/nav_sent"/>
            <item
                android:id="@+id/nav_trash"
                android:icon="@android:drawable/ic_menu_delete"
                android:title="@string/nav_trash"/>
        group>
        <item android:title="@string/nav_support">
            <menu>
                <item
                    android:id="@+id/nav_help"
                    android:icon="@android:drawable/ic_menu_help"
                    android:title="@string/nav_help"/>
                <item
                    android:id="@+id/nav_feedback"
                    android:icon="@android:drawable/sym_action_email"
                    android:title="@string/nav_feedback"/>
            menu>
        item>
    menu>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    向活动布局中增加一个抽屉布局,作为它的根元素。这个抽屉布局需要包含两个内容:一个包含活动内容的视图或视图组作为它的第一个元素,以及一个定义抽屉的导航视图作为它的第二个元素。
    完整的activity_main.xml代码:

    
    <androidx.drawerlayout.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">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" >
    
            <include
                layout="@layout/toolbar_main"
                android:id="@+id/toolbar" />
    
            <FrameLayout
                android:id="@+id/content_frame"
                android:layout_height="match_parent"
                android:layout_width="match_parent" />
    
        LinearLayout>
    
        <com.google.android.material.navigation.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            app:headerLayout="@layout/nav_header"
            app:menu="@menu/menu_nav"/>
    
    androidx.drawerlayout.widget.DrawerLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    下面更新MainActivity

    package com.hafd.catchat;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.widget.Toolbar;
    import androidx.fragment.app.Fragment;
    import androidx.fragment.app.FragmentTransaction;
    import android.os.Bundle;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
    
            Fragment fragment = new InboxFragment();
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.content_frame, fragment);
            ft.commit();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    六、增加抽屉开关

    首先增加两个字符串资源来描述打开抽屉和关闭抽屉。

        <string name="nav_open_drawer">Open navigation drawerstring>
        <string name="nav_close_drawer">Close navigation drawerstring>
    
    • 1
    • 2

    完整的MainActivity

    package com.hafd.catchat;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.ActionBarDrawerToggle;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.widget.Toolbar;
    import androidx.core.view.GravityCompat;
    import androidx.drawerlayout.widget.DrawerLayout;
    import androidx.fragment.app.Fragment;
    import androidx.fragment.app.FragmentTransaction;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.Gravity;
    import android.view.MenuItem;
    
    import com.google.android.material.navigation.NavigationView;
    
    public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
    
            //增加一个抽屉开关
            DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout);
            ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.nav_open_drawer, R.string.nav_close_drawer);
            drawer.addDrawerListener(toggle);
            toggle.syncState();
            //将活动注册为导航视图的一个监听器
            NavigationView navigationView = (NavigationView)findViewById(R.id.nav_view);
            navigationView.setNavigationItemSelectedListener(this);
    
            Fragment fragment = new InboxFragment();
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.content_frame, fragment);
            ft.commit();
        }
    
        //用户单击某一项时会调用这个方法
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            int id = item.getItemId();
            Fragment fragment = null;
            Intent intent = null;
    
            if (id == R.id.nav_drafts)fragment = new DraftsFragment();
            else if (id == R.id.nav_sent)fragment = new SentItemsFragment();
            else if (id == R.id.nav_trash)fragment = new TrashFragment();
            else if (id == R.id.nav_help)intent = new Intent(this, HelpActivity.class);
            else if (id == R.id.nav_feedback)intent = new Intent(this, FeedbackActivity.class);
            else fragment = new InboxFragment();
    
            //根据用户在抽屉中选择的选项,显示相应的片段和活动
            if (fragment != null) {
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                ft.replace(R.id.content_frame, fragment);
                ft.commit();
            }else startActivity(intent);
    
            DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            //用户单击某一项时关闭抽屉
            drawer.closeDrawer(GravityCompat.START);
            return true;
        }
    
        //后退时,关闭抽屉
        @Override
        public void onBackPressed() {
            DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout);
            if (drawer.isDrawerOpen(GravityCompat.START))drawer.closeDrawer(GravityCompat.START);
            else super.onBackPressed();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    试一试
    在这里插入图片描述

  • 相关阅读:
    MySQL怎么运行的系列(十)Innodb中的锁:记录锁、临键锁、间隙锁、意向锁
    【gzoj】鸡蛋的硬度【基础概率DP】
    傅里叶分析(2)
    idea compile项目正常,启动项目的时候build失败,报“找不到符号”等问题
    Matten:视频生成与Mamba-Attention
    Revit中有序地命名很眼花?那你是不知道『视图命名』
    Fiddler(六) - http请求的结果分析-创建一个自己的响应
    第四十七章 命名空间和数据库 - %SYS 命名空间
    卡码网语言基础课 |句子缩写
    2023年【氧化工艺】考试内容及氧化工艺操作证考试
  • 原文地址:https://blog.csdn.net/weixin_44014982/article/details/133362978