12.3--滑动菜单

2023-10-13 19:40
文章标签 滑动 菜单 12.3

本文主要是介绍12.3--滑动菜单,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

滑动菜单可以说是 Material Design 中最常见的效果之一了,在许多著名的应用(如 Gmail、 Google Photo等)中,都有滑动菜单的功能。虽说这个功能看上去好像挺复杂的,不过借助Google提供的各种工具,我们可以很轻松地实现非常炫醋的滑动菜单效果,那么我们马上开始吧。

 

12.3.1 DrawerLayout

所谓的滑动菜单就是将一些萊单选项隐藏起来,而不是放置在主屏幕上,然后可以通过滑动的方式将菜单显示出来。这种方式既节省了屏幕空间,又实现了非常好的动画效果,是 Material Design 中推荐的做法。

不过如果我们全靠自己去实现上述功能的话,难度恐怕就很大了。幸运的是,Google 在AndroidX 库中提供了 一个DrawerLayout 控件,借助这个控件,实现滑动菜单简单又方便。

先来简单介绍一下 DrawerLayout 的用法吧。首先它是一个布局,在布局中允许放人两个直接子控件,第一个子控件是主屏幕中显示的内容,第二个子控件是滑动菜单中显示的内容。因此我们就可以对 activity_main.xml 中的代码做如下修改:

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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"xmlns:app="http://schemas.android.com/apk/res-auto"tools:context=".MainActivity"><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><androidx.appcompat.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="@color/colorPrimary"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/></FrameLayout><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="start"android:background="#fff"android:text="This is menu"android:textSize="30sp"/></androidx.drawerlayout.widget.DrawerLayout>

可以看到,这里最外层的控件使用了 DrawerLayout,DrawerLayout 中放置了两个直接子控件;

第一个子控件是 FrameLayout,用于作为主屏暮中显示的内容,当然里面还有我们刚刚定义的 Toolbar。

第二个子控件这里使用了一个 TextView,用于作为滑动菜单中显示的内容,其实使用什么都可以,DrawerLayout 并没有限制只能使用固定的控件。

但是关于第二个子控件有一点需要注意,Layout_gravity 这个属性是必须指定的,因为我们需要告诉 DrawerLayout 滑动菜单是在屏幕的左边还是右边,指定 left 表示滑动菜单在左边,指定 right 表示滑动菜单在右边。这里我指定了 start,表示会根据系统语言进行判断,如果系统语言是从左往右的,比如英语、汉语,滑动菜单就在左边,如果系统语言是从右往左的,比如阿拉伯语,滑动菜单就在右边。

没错,只需要改动这么多就可以了,现在重新运行一下程序,然后在屏幕的左侧边缘向右拖动,就可以让滑动菜单显示出来了,如图所示。

然后向左滑动菜单,或者点击一下菜单以外的区域,都可以让滑动菜单关闭,从而回到主界面。无论是展示还是隐藏滑动菜单,都是有非常流畅的动画过渡的。

可以看到,我们只是稍微改动了一下布局文件,就能实现如此炫醋的效果,是不是觉得挺激动呢?不过现在的滑动菜单还有点问题,因为只有在屏幕的左侧边缘进行拖动时才能将菜单拖出来,而很多用户可能根本就不知道有这个功能,那么该怎么提示他们呢?

Material Design 建议的做法是在 Toolbar 的最左边加入一个导航按钮,点击了按钮也会将滑动菜单的内容展示出来。这样就相当于给用户提供了两种打开滑动菜单的方式,防止一些用户不知道屏幕的左侧边缘是可以拖动的。

下面我们开始来实现这个功能。首先我准备了一张导航按钮的图标 ic_menu.png,将它放在了 drawable-xxhdpi 目录下。然后修改 MainActivity 中的代码,如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)setSupportActionBar(toolbar)supportActionBar?.let {it.setDisplayHomeAsUpEnabled(true)it.setHomeAsUpIndicator(R.drawable.ic_menu)}}override fun onCreateOptionsMenu(menu: Menu?): Boolean {menuInflater.inflate(R.menu.toolbar,menu)return true}override fun onOptionsItemSelected(item: MenuItem): Boolean {when(item.itemId){...android.R.id.home -> drawerLayout.openDrawer(GravityCompat.START)}return true}
}

这里我们并没有改动多少代码,首先调用getSupportActionBar() 方法得到了ActionBar的实例,虽然这个ActionBar 的具体实现是由Toolbar 来完成的。接着在ActionBar 不为空的情况下调用setDisplayHomeAsUpEnabled() 方法让导航按钮显示出来,调用setHomeAsUpIndicator() 方法来设置一个导航按钮图标。实际上,Toolbar 最左侧的这个按钮就叫做Home 按钮,它默认的图标是一个返回箭头,含义是返回上一个Activity。很明显,这里我们将它默认的样式和作用都进行了修改

接下来,在onOptionsItemSelected() 方法中对 Home 按钮的点击事件进行处理,Home 按钮的id 永远是android.R.id.home。然后调用DrawerLayout 的openDrawer() 方法将滑动菜单展示出来,注意,openDrawer() 方法要求传入一个Gravity 参数,为了保证这里的行为和XML 中定义的一致,我们传入了GravityCompat.START。

现在重新运行一下程序,效果如图所示。

可以看到,在 Toolbar 的最左边出现了一个导航按钮,用户看到这个按钮就知道这肯定是可以点击的。现在点击一下这个按钮,滑动菜单界面就会再次展示出来了。

 

12.3.2 NavigationView

目前我们已经成功实现了滑动菜单功能,其中滑动功能已经做得非常好了,但是菜单却还很丑,毕竟菜单页面仅仅使用了一个 TextView,非常单调。有对比才会有落差,我们看一下Play Store 的滑动菜单页面是长什么样的,如图所示。

 

类似这样的,但凡是黑白图片都是从第二版 的PDF 中截取的。

经过对比之后是不是党得我们的滑动菜单页面更丑了?不过没关系,优化滑动菜单页面,这就是我们本小节的全部目标。

事实上,你可以在滑动菜单页面定制任意的布局,不过Google给我们提供了一种更好的方法 ——使用 NavigationView。NavigationView 是 Design Support 库中提供的一个控件,它不仅是严格按照 Material Design 的要求来进行设计的,而且还可以将滑动菜单页面的实现变得非常简单。接下来我们就学习ー下 NavigationView 的用法。

首先,既然这个控件是Material 库中提供的,那么我们就需要将这个库引入项目中才行。打开app/build.gradle 文件,在dependencies 闭包中添加如下内容:

dependencies {...implementation 'com.google.android.material:material:1.0.0'implementation 'de.hdodenhof:circleimageview:3.0.1'
}

这里添加了两行依赖关系,第一行就是 Material 库,第二行是一个开源项目 CirclelmageView,它可以用来轻松实现图片圆形化的功能,我们待会就会用到它。

在开始使用 NavigationView 之前,我们还需要提前准备好两个东西:menu 和 headerLayout。menu 是用来在 NavigationView 中显示具体的菜单项的,headerLayout 则是用来在 NavigationView 中显示头部布局的。

先来准备 menu,这里我事先找了几张图片来作为按钮的图标,并将它们放在了drawable-xxhdpi 目录下。右击 menu 文件夹→New→ Menu resource file,创建一个 nav_menu.xml 文件,并编写如下代码:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><group android:checkableBehavior="single"><itemandroid:id="@+id/navCall"android:icon="@drawable/nav_call"android:title="Call"/><itemandroid:id="@+id/navFriends"android:icon="@drawable/nav_friends"android:title="Friends"/><itemandroid:id="@+id/navLocation"android:icon="@drawable/nav_location"android:title="Location"/><itemandroid:id="@+id/navMail"android:icon="@drawable/nav_mail"android:title="Mail"/><itemandroid:id="@+id/navTask"android:icon="@drawable/nav_task"android:title="Tasks"/></group>
</menu>

我们首先在<menu> 中嵌套了一个<group>标签,然后将group 的 checkableBahavior 属性指定为single。group 表示一个组,checkableBehavior 指定为single 表示组中的所有菜单项只能单选

下面我们来看一下这些菜单项吧。这里一共定义了5个item,分别使用android:id 属性指定菜单项的id,android:icon 属性指定菜单项的图标,android:title 指定菜单项显示的文字。就是这么简单,现在我们已经把menu 准备好了。

接下来应该准备 headerLayout 了,这是一个可以随意定制的布局,不过我并不想将它做得太复杂。这里简单起见,我们就在 headerLayout 中放置头像、用户名、邮箱地址这 3 项内容吧。

说到头像,那我们还需要再准备一张图片,这里我找了一张宠物图片,并把它放在了 drawable-xxhdpi 目录下。另外这张图片最好是一张正方形图片,因为待会我们会把它圆形化。然后右击 layout 文件夹→New→ Layout resource file,创建一个 nav_header.xml 文件。修改其中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="180dp"android:padding="10dp"android:background="@color/colorPrimary"><de.hdodenhof.circleimageview.CircleImageViewandroid:id="@+id/iconImage"android:layout_width="70dp"android:layout_height="70dp"android:src="@drawable/nav_icon"android:layout_centerInParent="true"/><TextViewandroid:id="@+id/mailText"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:text="tonygreendev@gmail.com"android:textColor="#fff"android:textSize="14sp"/><TextViewandroid:id="@+id/userText"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_above="@id/mailText"android:text="Tony Green"android:textColor="#fff"android:textSize="14sp"/></RelativeLayout>

可以看到, 布局文件的最外层是一个RelativeLayout,我们将它的宽度设为match_parent,高度设置为180dp,这是一个NavigationView 比较合适的高度,然后指定它的背景色为colorPrimary。

在 Relative Layout I 中我们放置了 3 个控件,CirclelmageView 是一个用于将图片圆形化的控件它的用法非常简单,基本和 ImageView 是完全一样的,这里给它指定了一张图片作为头像,然后设置为居中显示。另外两个 TextView 分别用于显示用户名和邮箱地址,它们都用到了一些 RelativeLayout 的定位属性,相信肯定难不倒你吧?

现在 menu 和 headerLayout 都准备好了,我们终于可以使用 NavigationView 了。修改 activity_main xml 中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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"xmlns:app="http://schemas.android.com/apk/res-auto"tools:context=".MainActivity"><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><androidx.appcompat.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="@color/colorPrimary"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/></FrameLayout><com.google.android.material.navigation.NavigationViewandroid:id="@+id/navView"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="start"app:menu="@menu/nav_menu"app:headerLayout="@layout/nav_header"></com.google.android.material.navigation.NavigationView></androidx.drawerlayout.widget.DrawerLayout>

可以看到,我们将之前的 Textview 换成了 NavigationView,这样滑动菜单中显示的内容也就变成 NavigationView 了。这里又通过 app: menu 和 app: headerLayout 属性将我们刚才准备好的 menu 和 headerLayout 设置了进去,这样 NavigationView 就定义完成了。

NavigationView 虽然定义完成了,但是我们还要去处理菜单项的点击事件才行。修改 MainActivity 中的代码,如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)setSupportActionBar(toolbar)supportActionBar?.let {it.setDisplayHomeAsUpEnabled(true)it.setHomeAsUpIndicator(R.drawable.ic_menu)}navView.setCheckedItem(R.id.navCall)navView.setNavigationItemSelectedListener {drawerLayout.closeDrawers()true}}override fun onCreateOptionsMenu(menu: Menu?): Boolean {menuInflater.inflate(R.menu.toolbar,menu)return true}override fun onOptionsItemSelected(item: MenuItem): Boolean {when(item.itemId){R.id.backup -> Toast.makeText(this,"You clicked Backup",Toast.LENGTH_SHORT).show()R.id.delete -> Toast.makeText(this,"You clicked Delete",Toast.LENGTH_SHORT).show()R.id.settings -> Toast.makeText(this,"You clicked Settings",Toast.LENGTH_SHORT).show()android.R.id.home -> drawerLayout.openDrawer(GravityCompat.START)}return true}
}

代码还是比较简单的,这里我们首先调用了Navigation 的setCheckedItem() 方法将Call 菜单项设置为默认选中。接着调用了setNavigationItemSelectedListener() 方法来设置一个菜单选中事件的监听器,当用户一点击了任意菜单项时,就会回调到传入Lamda 表达式当中,我们可以在这里编写具体的逻辑处理。这里调用了DrawerLayout 的closeDrawers() 方法将滑动菜单关闭,并返回了一个true 表示此事件已经被处理。

现在可以重新运行一下程序了,点击一下 Toolbar 左側的导航按钮,效果如图所示。

怎么样?这样的滑动菜单页面,你无论如何也不能说它丑了吧?Material Design 的魅力就在这里,它真的是一种非常美观的设计理念,只要你按照它的各种规范和建议来设计界面,最终做出来的程序就是特别好看的。

相信你对现在做出来的效果也一定十分满意吧?不过不要满足于现状,后面我们会实现更加炫酷的效果。跟紧脚步,继续学习。

 

 

这篇关于12.3--滑动菜单的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/205421

相关文章

基于Redis有序集合实现滑动窗口限流的步骤

《基于Redis有序集合实现滑动窗口限流的步骤》滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis... 滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

Windows如何添加右键新建菜单

Windows如何添加右键新建菜单 文章目录 Windows如何添加右键新建菜单实验环境缘起以新建`.md`文件为例第一步第二步第三步 总结 实验环境 Windows7 缘起 因为我习惯用 Markdown 格式写文本,每次新建一个.txt后都要手动修改为.md,真的麻烦。如何在右键新建菜单中添加.md选项呢? 网上有很多方法,这些方法我都尝试了,要么太麻烦,要么不凑效

专题二_滑动窗口_算法专题详细总结

目录 滑动窗口,引入: 滑动窗口,本质:就是同向双指针; 1.⻓度最⼩的⼦数组(medium) 1.解析:给我们一个数组nums,要我们找出最小子数组的和==target,首先想到的就是暴力解法 1)暴力: 2)优化,滑动窗口: 1.进窗口 2.出窗口 3.更新值 2.⽆重复字符的最⻓⼦串(medium) 1)仍然是暴力解法: 2)优化: 进窗口:hash[s[rig

hot100刷题第1-9题,三个专题哈希,双指针,滑动窗口

求满足条件的子数组,一般是前缀和、滑动窗口,经常结合哈希表; 区间操作元素,一般是前缀和、差分数组 数组有序,更大概率会用到二分搜索 目前已经掌握一些基本套路,重零刷起leetcode hot 100, 套路题按套路来,非套路题适当参考gpt解法。 一、梦开始的地方, 两数之和 class Solution:#注意要返回的是数组下标def twoSum(self, nums: Lis

【leetcode详解】考试的最大困扰度(滑动窗口典例)

实战总结: sum += answerKey[right] == c; 经典操作,将判断语句转化为0, 1接收来计数//大问题分解: 对'T'还是'F'做修改, 传参为c//滑动窗口: 遍历, 维护left& right指向 及 c的个数, 更新不知从何下手写代码时:考虑先写好第一次的,然后以此为基础补充代码以适后续情况 题面: 解题感受: 思路总体好想, 实现略有挑战。 思路分析:

【每日一题】LeetCode 2379.得到K个黑块的最少涂色次数(字符串、滑动窗口)

【每日一题】LeetCode 2379.得到K个黑块的最少涂色次数(字符串、滑动窗口) 题目描述 给定一个字符串 blocks,其中每个字符代表一个颜色块,可以是 ‘W’(白色)或 ‘B’(黑色)。你需要找到一个至少包含 k 个连续黑色块的子串。每次操作可以将一个白色块变成黑色块。你的任务是找到至少出现一次连续 k 个黑色块的最少操作次数。 和该题目类似:【每日一题】LeetCode 202

【视频教程】手把手AppWizard轻松制作一个emWin滑动主界面控制框架,任意跳转控制(2024-09-06)

现在的新版AppWizard已经比较好用,用户可以轻松的创建各种项目常规界面。 比如早期创建一个支持滑动的主界面框架,并且可以跳转各种子界面,仅仅界面布局和各种图片格式转换都要花不少时间,而现在使用AppWizard,可以说轻轻松松,毫不费力。 用户唯一要做的就是根据自己的芯片性能做一定的速度优化。 视频: https://www.bilibili.com/video/BV17Rp3eLE

Flutter-listview的item左右滑动,删除item

import 'package:flutter/material.dart';//列表左右滑动删除void main() =>runApp(MaterialApp(home: HomePage(),));class HomePage extends StatelessWidget {final List<String> items = List.generate(20, (index) =>

如何在Qt的widget上右键显示菜单

如何在Qt的widget上右键显示菜单 今天早上一来,我老大叫我在widget上点击右键加上一个菜单,并相应其响应的功能,因为我成刚接触Qt,所以看了下QtGUI编程这本书,做出来,记录下来,说不定哪天还用得上啊! 废话不多说,直接上代码: 方法一: m_text = QTextCodec::codecForLocale(); ui->tableWidget->addAction(ne