Android开发-Android应用中仿网易云音乐抽屉式菜单栏的实现

前 言

要想在Android应用中实现和网易云音乐的抽屉式(侧滑)菜单栏一样效果的话需要用到Android中的“NavigationView”控件,该控件是在design包下,所以它是 Android 5.0 开始引入的 Material Design 设计特性。

Material Design 是由 Google 的设计工程师们基于传统优秀的设计原则,结合丰富的创意和科学技术所发明的一套全新的界面设计语言,包含了视觉、运动、互动效果等特性。它是 Google 在2014年 Google I/O 大会上重磅推出了一套全新的界面设计语言,也是 Android 5.0 的新特性。

编码前的准备工作

因为“NavigationView”控件是在在design包下的,所以首先打开您应用的应用级 build.gradle 文件,并找到“dependencies”部分,添加design包的依赖库,如 build.gradle 示例(节选)。

dependencies {
    ...
   implementation 'com.android.support:design:28.0.0'
}

新建一个布局文件activity_home_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/color_page_bg"
    android:orientation="vertical">

    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <include
            android:id="@+id/include"
            layout="@layout/app_bar_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <!--去掉background,会影响4.4系统的状态栏-->
        <android.support.design.widget.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:background="@color/color_page_bg"
            android:fitsSystemWindows="true" />

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

</LinearLayout>

在该布局界面的中的“NavigationView”布局外层是由“DrawerLayout”布局嵌套着,这样做的目的是更能较好的在父布局实现手势侧滑打开或者关闭抽屉式菜单栏。还有在“NavigationView”布局里要设置android:background属性,如果不设置的话会影响Android 4.4 系统的状态栏样式效果。

新建一个主页HomeActivity.java的Activity类

public class HomeActivity extends BaseActivity {

    public static HomeActivity instance;
    // 头像URL
    public static final String IC_AVATAR = "https://clouddisc.oss-cn-hongkong.aliyuncs.com/image/ic_user.png?x-oss-process=style/thumb";

    private long exitTime = 0;

    @BindView(R.id.drawer_layout)
    DrawerLayout drawerLayout;
    @BindView(R.id.nav_view)
    NavigationView navView;

    @BindView(R.id.vp_content)
    ViewPager vp_content;

    private List<Fragment> mFragment;
    @BindView(R.id.iv_title_one)
    ImageView ivTitleOne;
    @BindView(R.id.iv_title_two)
    ImageView ivTitleTwo;
    @BindView(R.id.iv_title_three)
    ImageView ivTitleThree;

    @Override
    protected int getLayoutId() {
        instance = this;
        return R.layout.activity_home_layout;
    }

    @Override
    protected void initView() {
        ButterKnife.bind(this);
        StatusBarUtil.setColorNoTranslucentForDrawerLayout(this, drawerLayout,
                this.getResources().getColor(R.color.colorTheme));
        initDrawerLayout();
        initContentFragment();
    }

    @Override
    protected void initData() {

    }

    private void initDrawerLayout() {
        navView.inflateHeaderView(R.layout.nav_header_main);
        View headerView = navView.getHeaderView(0);
        ImageView iv_avatar = headerView.findViewById(R.id.iv_avatar);
        GlideUtil.displayCircle(iv_avatar, IC_AVATAR);
        LinearLayout ll_nav_account = headerView.findViewById(R.id.ll_nav_account);
        ll_nav_account.setOnClickListener(listener);
        LinearLayout ll_nav_password = headerView.findViewById(R.id.ll_nav_password);
        ll_nav_password.setOnClickListener(listener);
        LinearLayout ll_nav_feedback = headerView.findViewById(R.id.ll_nav_feedback);
        ll_nav_feedback.setOnClickListener(listener);
        LinearLayout ll_nav_version_update = headerView.findViewById(R.id.ll_nav_version_update);
        ll_nav_version_update.setOnClickListener(listener);
        LinearLayout ll_nav_score = headerView.findViewById(R.id.ll_nav_score);
        ll_nav_score.setOnClickListener(listener);
        LinearLayout ll_nav_account_switch = headerView.findViewById(R.id.ll_nav_account_switch);
        ll_nav_account_switch.setOnClickListener(listener);

        LinearLayout ll_nav_logout = headerView.findViewById(R.id.ll_nav_logout);
        ll_nav_logout.setOnClickListener(this::onClick);

    }

    private PerfectClickListener listener = new PerfectClickListener() {

        @Override
        protected void onNoDoubleClick(final View v) {
            drawerLayout.closeDrawer(GravityCompat.START);
            drawerLayout.postDelayed(() -> {
                switch (v.getId()) {
                    case R.id.ll_nav_account:
                        ToastUtil.showToast("个人中心");
                        Intent accountIntent = new Intent(HomeActivity.this, TestActivity.class);
                        accountIntent.putExtra("text", "个人中心");
                        startActivity(accountIntent);
                        break;
                    case R.id.ll_nav_password:
                        ToastUtil.showToast("密码设置");
                        Intent passwordIntent = new Intent(HomeActivity.this, TestActivity.class);
                        passwordIntent.putExtra("text", "密码设置");
                        startActivity(passwordIntent);
                        break;
                    case R.id.ll_nav_feedback:
                        ToastUtil.showToast("意见反馈");
                        Intent feedbackIntent = new Intent(HomeActivity.this, TestActivity.class);
                        feedbackIntent.putExtra("text", "意见反馈");
                        startActivity(feedbackIntent);
                        break;
                    case R.id.ll_nav_version_update:
                        ToastUtil.showToast("版本更新");
                        Intent updateIntent = new Intent(HomeActivity.this, TestActivity.class);
                        updateIntent.putExtra("text", "版本更新");
                        startActivity(updateIntent);
                        break;
                    case R.id.ll_nav_score:
                        ToastUtil.showToast("给个评分呗");
                        Intent scoreIntent = new Intent(HomeActivity.this, TestActivity.class);
                        scoreIntent.putExtra("text", "给个评分呗");
                        startActivity(scoreIntent);
                        break;
                    case R.id.ll_nav_account_switch:
                        ToastUtil.showToast("切换账号");
                        Intent switchIntent = new Intent(HomeActivity.this, TestActivity.class);
                        switchIntent.putExtra("text", "切换账号");
                        startActivity(switchIntent);
                        break;
                    default:
                        break;
                }
            }, 260);
        }
    };

    private void initContentFragment() {

        mFragment = new ArrayList<>();
        mFragment.add(new MusicFragment());
        mFragment.add(new MovieFragment());
        mFragment.add(new MineFragment());
        //预加载最多的数量
        vp_content.setOffscreenPageLimit(2);
        //设置适配器
        vp_content.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            //选中的item
            @Override
            public Fragment getItem(int position) {
                return mFragment.get(position);
            }

            //返回item的个数
            @Override
            public int getCount() {
                return mFragment.size();
            }
        });
        // 设置默认加载第2个Fragment
        setCurrentItem(1);
        // ViewPager的滑动监听
        vp_content.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i1) {

            }

            @Override
            public void onPageSelected(int position) {
                setCurrentItem(position);
            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });

    }

    @OnClick({R.id.ll_title_menu, R.id.iv_title_one, R.id.iv_title_two, R.id.iv_title_three})
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ll_title_menu:
                // 开启抽屉式菜单
                drawerLayout.openDrawer(GravityCompat.START);
                break;
            case R.id.iv_title_one:
                // 这样做的目的是减少cpu的损耗
                if (vp_content.getCurrentItem() != 0) {
                    setCurrentItem(0);
                }
                break;
            case R.id.iv_title_two:
                if (vp_content.getCurrentItem() != 1) {
                    setCurrentItem(1);
                }
                break;
            case R.id.iv_title_three:
                if (vp_content.getCurrentItem() != 2) {
                    setCurrentItem(2);
                }
                break;
            case R.id.ll_nav_logout:
                // 退出登录
                finish();
                break;
            default:
                break;
        }
    }

    /**
     * 切换页面
     *
     * @param position 分类角标
     */
    private void setCurrentItem(int position) {
        boolean isOne = false;
        boolean isTwo = false;
        boolean isThree = false;
        switch (position) {
            case 0:
                isOne = true;
                break;
            case 1:
                isTwo = true;
                break;
            case 2:
                isThree = true;
                break;
            default:
                isTwo = true;
                break;
        }
        vp_content.setCurrentItem(position);
        ivTitleOne.setSelected(isOne);
        ivTitleTwo.setSelected(isTwo);
        ivTitleThree.setSelected(isThree);
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {

            if ((System.currentTimeMillis() - exitTime) > 2000) {
                ToastUtil.showToast("再按一次退出应用");
                exitTime = System.currentTimeMillis();
            } else {
//                    Intent intent = new Intent(Intent.ACTION_MAIN);
//                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//                    intent.addCategory(Intent.CATEGORY_HOME);
//                    startActivity(intent);
                finish();
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

}

该逻辑代码主要实现在宿主Activity中实现打开和关闭抽屉式菜单栏、抽屉式菜单栏item条目的点击事件以及加载切换三个Fragment界面,具体的代码逻辑实现可以看代码里的注释。在该宿主Activity中加载抽屉式菜单栏时还需要一个nav_header_main.xml布局界面,布局界面的样式如下。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/color_page_bg"
    android:orientation="vertical">

    <android.support.v4.widget.NestedScrollView
        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">

            <RelativeLayout
                android:id="@+id/ll_header_bg"
                android:layout_width="match_parent"
                android:layout_height="173dp"
                android:background="@drawable/homepage_header"
                android:gravity="bottom"
                android:orientation="vertical"
                android:theme="@style/ThemeOverlay.AppCompat.Dark">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="#4000"
                    android:gravity="bottom"
                    android:orientation="vertical"
                    android:paddingLeft="16dp"
                    android:paddingTop="16dp"
                    android:paddingRight="16dp"
                    android:paddingBottom="16dp">

                    <ImageView
                        android:id="@+id/iv_avatar"
                        android:layout_width="60dp"
                        android:layout_height="60dp"
                        android:scaleType="centerCrop" />

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal"
                        android:paddingTop="16dp">

                        <TextView
                            android:id="@+id/tv_username"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:text="_彼岸雨敲窗_"
                            android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                            android:textColor="@color/colorWhite"
                            android:textSize="17sp" />

                        <TextView
                            android:id="@+id/tv_level"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_gravity="center_vertical"
                            android:layout_marginLeft="6dp"
                            android:background="@drawable/shape_bg_level"
                            android:gravity="center"
                            android:paddingLeft="6dp"
                            android:paddingTop="1dp"
                            android:paddingRight="6dp"
                            android:paddingBottom="1dp"
                            android:text="Lv.100"
                            android:textColor="@color/colorWhite"
                            android:textSize="10sp"
                            android:textStyle="italic|bold" />

                    </LinearLayout>

                </LinearLayout>

            </RelativeLayout>

            <LinearLayout
                android:id="@+id/ll_nav_account"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:layout_marginTop="8dp"
                android:background="?attr/selectableItemBackground"
                android:clickable="true"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingLeft="16dp"
                android:paddingRight="16dp">

                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/user_icon" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dp"
                    android:drawableEnd="@drawable/arrow_right"
                    android:text="个人中心"
                    android:textColor="@color/colorContent"
                    android:textSize="15sp" />

            </LinearLayout>

            <LinearLayout
                android:id="@+id/ll_nav_password"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:background="?attr/selectableItemBackground"
                android:clickable="true"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingLeft="16dp"
                android:paddingRight="16dp">

                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/password_icon" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dp"
                    android:drawableEnd="@drawable/arrow_right"
                    android:text="密码设置"
                    android:textColor="@color/colorContent"
                    android:textSize="15sp" />

            </LinearLayout>

            <LinearLayout
                android:id="@+id/ll_nav_feedback"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:background="?attr/selectableItemBackground"
                android:clickable="true"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingLeft="16dp"
                android:paddingRight="16dp">

                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/feedback_icon" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dp"
                    android:drawableEnd="@drawable/arrow_right"
                    android:text="意见反馈"
                    android:textColor="@color/colorContent"
                    android:textSize="15sp" />

            </LinearLayout>

            <LinearLayout
                android:id="@+id/ll_nav_version_update"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:background="?attr/selectableItemBackground"
                android:clickable="true"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingLeft="16dp"
                android:paddingRight="16dp">

                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/update_icon" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dp"
                    android:drawableEnd="@drawable/arrow_right"
                    android:text="版本更新"
                    android:textColor="@color/colorContent"
                    android:textSize="15sp" />

            </LinearLayout>

            <LinearLayout
                android:id="@+id/ll_nav_score"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:background="?attr/selectableItemBackground"
                android:clickable="true"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingLeft="16dp"
                android:paddingRight="16dp">

                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/score_icon" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dp"
                    android:drawableEnd="@drawable/arrow_right"
                    android:text="给个评分呗"
                    android:textColor="@color/colorContent"
                    android:textSize="15sp" />

            </LinearLayout>

            <View
                android:layout_width="match_parent"
                android:layout_height="0.3dp"
                android:background="@color/colorNavLine" />

            <LinearLayout
                android:id="@+id/ll_nav_account_switch"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:background="?attr/selectableItemBackground"
                android:clickable="true"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingLeft="16dp"
                android:paddingRight="16dp">

                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/account_switch_icon" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dp"
                    android:drawableEnd="@drawable/arrow_right"
                    android:text="切换账号"
                    android:textColor="@color/colorContent"
                    android:textSize="15sp" />

            </LinearLayout>

            <LinearLayout
                android:id="@+id/ll_nav_logout"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:background="?attr/selectableItemBackground"
                android:clickable="true"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingLeft="16dp"
                android:paddingRight="16dp">

                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/logout_icon" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dp"
                    android:drawableEnd="@drawable/arrow_right"
                    android:text="退出登录"
                    android:textColor="@color/colorContent"
                    android:textSize="15sp" />

            </LinearLayout>

        </LinearLayout>

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

</LinearLayout>

界面运行效果图如下:
在这里插入图片描述

apk安装包下载体验地址:

可以扫描以下二维码进行下载安装,或者点击以下链接 https://fir.im/dmenu 进行下载安装体验。
在这里插入图片描述
———————— The end ————————

码字不易,如果您觉得这篇博客写的比较好的话,可以赞赏一杯咖啡吧~~
在这里插入图片描述


Demo程序源码下载地址一(GitHub)
Demo程序源码下载地址二(码云)

发布了72 篇原创文章 · 获赞 154 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/fukaimei/article/details/97748189