詳解Android如何實(shí)現(xiàn)好的彈層體驗(yàn)效果
前言
當(dāng)前 App 的設(shè)計(jì)趨勢(shì)越來(lái)越希望給用戶(hù)沉浸式體驗(yàn),這種設(shè)計(jì)會(huì)讓用戶(hù)盡量停留在當(dāng)前的界面,而不需要太多的跳轉(zhuǎn),這就需要引入彈層。比如,抖音引入購(gòu)物功能后,就實(shí)現(xiàn)了在觀(guān)看視頻界面可以通過(guò)彈層完成加入購(gòu)物車(chē)、下單操作,無(wú)需離開(kāi)當(dāng)前的視頻界面。本篇我們就來(lái)講講彈層這塊需要注意哪些用戶(hù)體驗(yàn)。
彈層的形式選擇
彈層從形式上來(lái)說(shuō)有中間彈層、左側(cè)彈層、右側(cè)彈層、底部彈層和頂部彈層,如下圖所示。

移動(dòng)端經(jīng)過(guò)這么多年的發(fā)展,不同的彈層的應(yīng)用場(chǎng)景相對(duì)來(lái)說(shuō)比較固定。因此,在選擇的時(shí)候,建議遵循現(xiàn)有的習(xí)慣來(lái)選擇合適的彈層。
- 中間彈層:通常用于詢(xún)問(wèn)對(duì)話(huà)框形式,例如退出登錄、刪除操作的二次確認(rèn)。
- 左側(cè)彈層:通常用于抽屜式的個(gè)人中心或設(shè)置界面,這種一般是底部欄無(wú)法放下個(gè)人中心類(lèi)界面的時(shí)候一個(gè)不錯(cuò)的選擇。
- 右側(cè)彈層:通常用于做數(shù)據(jù)篩選,典型的場(chǎng)景是購(gòu)物類(lèi)應(yīng)用的精準(zhǔn)篩選。
- 底部彈層:這種非常常見(jiàn),如我們提到的目前抖音的商品購(gòu)買(mǎi),還有像單選、多選、級(jí)聯(lián)選擇、時(shí)間選擇等等。
- 頂部彈層:頂部彈層一般也是用于篩選,比較常見(jiàn)的是列表表頭的篩選,或者導(dǎo)航欄帶類(lèi)似 PC 端的下拉類(lèi)的篩選。
這里需要提兩個(gè)比較通用的原則:
彈層出現(xiàn)的位置應(yīng)當(dāng)盡量靠近觸發(fā)交互的位置,比如點(diǎn)擊導(dǎo)航欄左上角的按鈕通常會(huì)從左側(cè)彈出。
蒙層的顏色要根據(jù)實(shí)際情況來(lái)定,一般都是黑色半透明的蒙層,但是主要面對(duì)是為了讓用戶(hù)能夠看清蒙層底下的內(nèi)容,比如如果是在視頻播放頁(yè)面疊加蒙層就會(huì)影響用戶(hù)體驗(yàn)了。
接下來(lái)我們依次來(lái)用 Flutter 實(shí)現(xiàn)上述的5類(lèi)彈層,并講講一些體驗(yàn)要點(diǎn)。
中間彈層
中間彈層在 Flutter中可以通過(guò)showDialog 和 ShowCupertinoDialog(iOS 風(fēng)格)實(shí)現(xiàn),下面是示例代碼。
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => AlertDialog(
title: const Text('操作提醒'),
content: const Text('確認(rèn)要進(jìn)行此操作嗎?'),
actionsAlignment: MainAxisAlignment.end,
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('取消'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'刪除',
style: TextStyle(color: Colors.red),
),
),
],
),
);這里有一個(gè)體驗(yàn)要素是是否支持點(diǎn)擊底部的黑色蒙層隱藏彈層。通常來(lái)說(shuō),如果是二次確認(rèn)類(lèi)操作,建議不要點(diǎn)擊蒙層隱藏。因?yàn)橛脩?hù)的操作目的性非常明確,如果不小心誤觸的話(huà),用戶(hù)還得再點(diǎn)擊一次。這個(gè)時(shí)候需要設(shè)置barrierDismissible為 false。
左右抽屜彈層
在 Flutter 的 Scaffold 中 提供了兩個(gè)屬性來(lái)設(shè)置左側(cè)抽屜和右側(cè)抽屜彈層,對(duì)應(yīng)的參數(shù)分別是 drawer 和 endDrawer。我們來(lái)看看具體的代碼。
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('左右抽屜彈層'),
backgroundColor: Colors.red[800],
leading: Builder(builder: (context) {
return IconButton(
onPressed: () {
Scaffold.of(context).openDrawer();
},
icon: const Icon(
Icons.menu,
),
);
}),
actions: [
Builder(builder: (context) {
return IconButton(
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
icon: const Icon(
Icons.filter_list_alt,
),
);
}),
],
),
drawer: Container(
width: MediaQuery.of(context).size.width * 3 / 4,
color: Colors.white,
child: Center(
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('收起'),
),
),
),
endDrawer: Container(
width: MediaQuery.of(context).size.width * 3 / 4,
color: Colors.blue,
child: Center(
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'收起',
style: TextStyle(
color: Colors.white,
),
),
),
),
),
body: const Center(child: Text('抽屜示例')),
);
}實(shí)現(xiàn)的效果如下圖所示。實(shí)用左側(cè)或右側(cè)彈層需注意三個(gè)體驗(yàn)要素:
- 寬度:建議設(shè)置為屏幕寬度的3/4,這種寬度抽屜的顯示內(nèi)容足夠?qū)挘紫碌拿蓪狱c(diǎn)擊區(qū)域?qū)挾纫脖容^合適點(diǎn)擊退出彈層。
- 頂部?jī)?nèi)容區(qū)域需要注意留出一定的頭部位置(比如左側(cè)通常會(huì)放頭像+昵稱(chēng)),一個(gè)是美觀(guān),一個(gè)是要避免顯示內(nèi)容碰到了手機(jī)屏幕的挖孔位置。
- 一般側(cè)邊彈層點(diǎn)擊蒙層都會(huì)支持收起,所以建議保留這個(gè)操作習(xí)慣,而不是非得點(diǎn)彈層的某個(gè)按鈕才關(guān)閉彈層。

頂部彈層
頂部彈層在 Flutter 中需要自己去實(shí)現(xiàn),一個(gè)比較好的方式是使用 showGeneralDialog來(lái)實(shí)現(xiàn)。這里有個(gè)技巧是實(shí)用 Column 組件可以讓內(nèi)容區(qū)靠頂部,然后利用動(dòng)畫(huà)實(shí)現(xiàn)從上往下滑的彈出效果。下面是實(shí)現(xiàn)代碼,實(shí)際通過(guò)這種方式可以實(shí)現(xiàn)底部,左側(cè),右側(cè)和中間的彈層。
showGeneralDialog(
context: context,
barrierDismissible: true,
transitionDuration: const Duration(milliseconds: 300),
barrierLabel: MaterialLocalizations.of(context).dialogLabel,
barrierColor: Colors.black.withOpacity(0.5),
pageBuilder: (context, _, __) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
color: Colors.white,
child: Card(
margin: const EdgeInsets.all(0),
child: ListView(
shrinkWrap: true,
children: <Widget>[
ListTile(
title: const Text('選項(xiàng) 1'),
onTap: () => Navigator.of(context).pop('1'),
),
ListTile(
title: const Text('選項(xiàng)2'),
onTap: () => Navigator.of(context).pop('2'),
),
ListTile(
title: const Text('選項(xiàng)3'),
onTap: () => Navigator.of(context).pop('3'),
),
],
),
),
),
],
);
},
transitionBuilder:
(context, animation, secondaryAnimation, child) {
return SlideTransition(
position: CurvedAnimation(
parent: animation,
curve: Curves.easeOut,
).drive(Tween<Offset>(
begin: const Offset(0, -1.0),
end: Offset.zero,
)),
child: child,
);
},
);效果如下所示,頂部彈層彈出的方向最好是從上到下,如果是從下到上的話(huà)移動(dòng)距離過(guò)長(zhǎng),會(huì)覺(jué)得很突兀。

底部彈層
底部彈層和頂部彈層其實(shí)是類(lèi)似的,而且更為常見(jiàn)一點(diǎn)。之前在文章底部彈窗ModelBottomSheet詳解有過(guò)介紹,這里就不再講具體實(shí)現(xiàn)了。說(shuō)一下底部彈層的幾個(gè)體驗(yàn)要點(diǎn):
- 彈出方向從底部往上彈出,動(dòng)畫(huà)時(shí)長(zhǎng)建議200-300毫秒;
- 如果是多選這種需要二次確認(rèn)操作的,需要在頂部提供確認(rèn)和取消按鈕;
- 適用選項(xiàng)不太多的場(chǎng)景,如果選擇的內(nèi)容很多建議單獨(dú)跳轉(zhuǎn)到選擇頁(yè)面完成,并且支持模糊搜索匹配選項(xiàng);
- 需要區(qū)分選中項(xiàng),讓用戶(hù)知道之前的選項(xiàng);
- 如果涉及到網(wǎng)絡(luò)請(qǐng)求,建議是在網(wǎng)絡(luò)請(qǐng)求完成后再關(guān)閉彈層,因?yàn)橛锌赡懿僮魇?dǎo)致用戶(hù)需要再次操作。
總結(jié)
本篇介紹了各類(lèi)彈層開(kāi)發(fā)過(guò)程的體驗(yàn)注意點(diǎn),同時(shí)給出了示例代碼。隨著沉浸式體驗(yàn)的推動(dòng),彈層會(huì)越來(lái)越多,因此建議各位開(kāi)發(fā)同學(xué)也能夠多多思考彈層如何改善用戶(hù)體驗(yàn),雖然咱不是產(chǎn)品經(jīng)理也不是設(shè)計(jì)師,但是從開(kāi)發(fā)角度給產(chǎn)品和設(shè)計(jì)一些專(zhuān)業(yè)的意見(jiàn),也是能夠“提升話(huà)語(yǔ)權(quán)”的,嘿嘿!
以上就是詳解Android如何實(shí)現(xiàn)好的彈層體驗(yàn)效果的詳細(xì)內(nèi)容,更多關(guān)于Android彈層的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android支付寶客戶(hù)端html5網(wǎng)頁(yè)無(wú)法自動(dòng)關(guān)閉問(wèn)題的解決方法
這篇文章主要為大家詳細(xì)介紹了android支付寶客戶(hù)端html5網(wǎng)頁(yè)無(wú)法自動(dòng)關(guān)閉問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
Android中通過(guò)RxJava進(jìn)行響應(yīng)式程序設(shè)計(jì)的入門(mén)指南
響應(yīng)式編程在Android中的運(yùn)用是非常犀利的,比如在異常處理和調(diào)度器方面,這里我們將從生命周期等方面來(lái)講解Android中通過(guò)RxJava進(jìn)行響應(yīng)式程序設(shè)計(jì)的入門(mén)指南:2016-06-06
Android三種方式生成矢量圖之VectorDrawable類(lèi)使用詳解
這篇文章主要介紹了Android三種方式生成矢量圖的VectorDrawable類(lèi),2014年6月26日的I/O?2014開(kāi)發(fā)者大會(huì)上谷歌正式推出了Android?L,它帶來(lái)了全新的設(shè)計(jì)語(yǔ)言Material?Design,新的API也提供了這個(gè)類(lèi)VectorDrawable2023-02-02
Recycleview實(shí)現(xiàn)無(wú)限自動(dòng)輪播
這篇文章主要為大家詳細(xì)介紹了Recycleview實(shí)現(xiàn)無(wú)限自動(dòng)輪播,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07
Android usb設(shè)備權(quán)限查詢(xún)及自動(dòng)獲取詳解流程
本篇文章介紹了我想要獲取Android系統(tǒng)usb設(shè)備使用權(quán)限時(shí)遇到的問(wèn)題,以及解決該問(wèn)題的過(guò)程及思路,通讀本篇對(duì)大家的學(xué)習(xí)或工作具有一定的價(jià)值,需要的朋友可以參考下2021-10-10
Android使用CountDownTimer實(shí)現(xiàn)倒計(jì)時(shí)效果
這篇文章主要為大家詳細(xì)介紹了Android使用CountDownTimer實(shí)現(xiàn)倒計(jì)時(shí)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
導(dǎo)致adb無(wú)法啟動(dòng)的5種情況和解決方法
這篇文章主要介紹了導(dǎo)致adb無(wú)法啟動(dòng)的5種情況和解決方法,本文列舉了最常見(jiàn)的5種情況和對(duì)應(yīng)解決方法,需要的朋友可以參考下2015-04-04
Android?Jetpack?組件LiveData源碼解析
這篇文章主要為大家介紹了Android?Jetpack?組件LiveData源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Android App中使用Pull解析XML格式數(shù)據(jù)的使用示例
這篇文章主要介紹了Android App中使用Pull解析XML格式數(shù)據(jù)的使用示例,Pull是Android中自帶的XML解析器,Java里也是一樣用:D需要的朋友可以參考下2016-04-04

