Flutter仿微信通訊錄實(shí)現(xiàn)自定義導(dǎo)航條的示例代碼
某些頁面比如我們?cè)谶x擇聯(lián)系人或者某個(gè)城市的時(shí)候需要快速定位到我們需要的選項(xiàng),一般都會(huì)需要像微信通訊錄右邊有一個(gè)導(dǎo)航條一樣的功能,由A到Z進(jìn)行快速定位,本篇文章我們將自己來實(shí)現(xiàn)一個(gè)跟微信通訊錄同樣的功能。
關(guān)鍵點(diǎn):手勢(shì)定位滑動(dòng)、列表定位、手勢(shì)、列表聯(lián)動(dòng)。
準(zhǔn)備數(shù)據(jù),首先我們需要準(zhǔn)備導(dǎo)航目錄數(shù)據(jù),
List<String> _az = [ "☆", "A", "B", "C", "D", "E", "F", "G", "H", "I", "G", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ];
然后列表數(shù)據(jù),列表數(shù)據(jù)可以讓后臺(tái)給我們排序好,如果后臺(tái)不給我們排序,我們也可以自己排序進(jìn)行組裝, 這里用到一個(gè)插件,根據(jù)漢字獲取拼音首字母,我們自己就可以對(duì)這些數(shù)據(jù)進(jìn)行整理排序。
lpinyin: ^2.0.3
數(shù)據(jù)格式:一個(gè)NameBean對(duì)應(yīng)一個(gè)字母所在的列表,這是我們存儲(chǔ)正式列表數(shù)據(jù)的格式。
class NameBean { String? initial;// 字母導(dǎo)航 List<Name>? nameList;// 內(nèi)容列表 NameBean({ this.initial, this.nameList, }); } /// name : "老李" /// 這里我只放了一個(gè)name字段,以后擴(kuò)展內(nèi)容只需在這里新增字段就好了 class Name { String? name; Name({ this.name, }); }
接下來我們先做導(dǎo)航條:
實(shí)現(xiàn)思路: 導(dǎo)航條就是一個(gè)List列表,點(diǎn)擊、滑動(dòng)、松開會(huì)有不同的交互,我們根據(jù)不同的交互來進(jìn)行實(shí)現(xiàn),這里我們會(huì)用到官方的GestureDetector組件,專門用來進(jìn)行手勢(shì)識(shí)別。將每一個(gè)item的高度固定,通過手勢(shì)交互返回的位置數(shù)據(jù)來進(jìn)行返回我們想要的目錄。比如我的每一個(gè)目錄高度設(shè)置為20.
導(dǎo)航條代碼:點(diǎn)擊或者移動(dòng)的時(shí)候選中的目錄會(huì)有一個(gè)按壓效果,
GestureDetector( child: Container( margin: EdgeInsetsDirectional.only(top: 40), width: 40, // 導(dǎo)航條 child: ListView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (context, index) { return SizedBox( height: 20, // 這里做了一個(gè)按壓或移動(dòng)滑動(dòng)的觸發(fā)效果 child: Container( alignment: Alignment.center, decoration: BoxDecoration( color: currentIndex == index ? Colors.redAccent : null, shape: BoxShape.circle), child: Text( _az[index], style: TextStyle( color: currentIndex == index ? Colors.white : Colors.black87, ), ), ), ); }, itemCount: _az.length, )), //手指按下觸發(fā) 豎著劃就用onVertica XXX回調(diào) onVerticalDragDown: (DragDownDetails e) { //打印手指按下的位置(相對(duì)于屏幕) int i = e.localPosition.dy ~/ 20; // _scrollController.jumpTo(index: i); setState(() { currentIndex = i; }); }, //手指滑動(dòng)時(shí)會(huì)觸發(fā)此回調(diào) onVerticalDragUpdate: (DragUpdateDetails e) { //用戶手指滑動(dòng)時(shí),更新偏移 int i = e.localPosition.dy ~/ 20; _az.length; if (i >= 0 && i <= _az.length - 1) { if (i != currentIndex) { setState(() { // 當(dāng)前選中的index 默認(rèn)-1 currentIndex = i; }); print("滑動(dòng) ${_az[i]}"); } } }, // 手指抬起 onTapUp: (e) { // 手指抬起 setState(() { currentIndex = -1; }); }, // 移動(dòng)取消 onVerticalDragEnd: (e) { // 移動(dòng)取消 setState(() { currentIndex = -1; }); }, )
然后我們可以看到微信在滑動(dòng)的時(shí)候有個(gè)字母放大氣泡會(huì)跟隨著手勢(shì)移動(dòng)。
實(shí)現(xiàn)思路:
氣泡和導(dǎo)航條并列,并根據(jù)手勢(shì)位置更新上邊距即可,因?yàn)槲覀兊膶?dǎo)航條的每一個(gè)item的高度是固定的,所以我們就可以根據(jù)滑動(dòng)的位置計(jì)算出滑動(dòng)距離頂部的高度,這里氣泡可以讓UI切個(gè)背景圖,也可以自己用canvas畫一個(gè)。
氣泡繪制源碼:目前我在學(xué)習(xí)繪制組件,順便畫了一個(gè),可能不是最佳的,但這不重要~今天的重點(diǎn)不是它~~~
@override void paint(Canvas canvas, Size size) { // 原點(diǎn)移到左下角 canvas.translate(size.width / 2, size.height / 2); Paint paint = Paint() ..color = Colors.redAccent ..strokeWidth = 2 ..style = PaintingStyle.fill; Path path = Path(); // 繪制文字 path.lineTo(0, -size.width / 2); // path.conicTo(33, -28, 20, 0, 1); path.arcToPoint(Offset(size.width / 2, 0), radius: Radius.circular(size.width / 2), largeArc: true, clockwise: true); path.close(); var bounds = path.getBounds(); canvas.save(); canvas.translate(-bounds.width / 2, bounds.height / 2); canvas.rotate(pi * 1.2); canvas.drawPath(path, paint); canvas.restore(); // 繪制文字 var textPainter = TextPainter( text: TextSpan( text: text, style: TextStyle( fontSize: 24, foreground: Paint() ..style = PaintingStyle.fill ..color = Colors.white, )), textAlign: TextAlign.center, textDirection: TextDirection.ltr); textPainter.layout(); canvas.translate(-size.width, -size.height / 2); textPainter.paint(canvas, Offset(-size.width / 2.4, size.height / 1.2)); }
導(dǎo)航條、氣泡都完成了,接下來就非常簡單了,內(nèi)容的填充我們就不能用ListView了,這里我們需要一個(gè)官方的插件: scrollable_positioned_list: ^0.2.3
使用它可以定位到具體的item位置,這樣我們就可以進(jìn)行列表定位和導(dǎo)航條進(jìn)行聯(lián)動(dòng)了。
內(nèi)容代碼:
ScrollablePositionedList.builder( physics: BouncingScrollPhysics(), itemScrollController: _scrollController, itemBuilder: (context, index) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Container( padding: EdgeInsetsDirectional.only(start: 10), child: Text(dataList[index].initial ?? ""), color: Colors.grey.shade300, height: 30, width: double.infinity, alignment: Alignment.centerLeft, ), Container( padding: EdgeInsetsDirectional.only(start: 15), child: ListView.builder( // 禁用滑動(dòng)事件 physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (context, cityIndex) { return InkWell( child: Container( height: 40, child: Column( children: [ Expanded( child: Container( child: Text(dataList[index] .nameList?[cityIndex] .name ?? ""), alignment: Alignment.centerLeft, ), ), Divider( height: 0.5, ) ], ), ), onTap: () {}, ); }, itemCount: dataList[index].nameList?.length, ), ) ], ); }, itemCount: dataList.length, )
ScrollablePositionedList用法基本和ListView一直,只是它多了一個(gè)這個(gè)方法,可以定位到具體的item。
_scrollController.jumpTo(index: i);
看下最終效果:請(qǐng)忽略數(shù)據(jù)的重復(fù)...手動(dòng)填充數(shù)據(jù)太麻煩了,有哪里不懂可以交流哦
總結(jié):
通過這個(gè)組件我們可以簡單的了解Flutter的手勢(shì)交互操作,通過手勢(shì)識(shí)別我們可以實(shí)現(xiàn)很多有意思的組件,尤其結(jié)合繪制和動(dòng)畫可以做出來非常有意思的交互,所有的交互最終的底層都是通過手勢(shì)識(shí)別完成的,以后有時(shí)間研究下源碼再和大家分享~
以上就是Flutter仿微信通訊錄實(shí)現(xiàn)自定義導(dǎo)航條的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Flutter微信導(dǎo)航條的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android人臉識(shí)別Demo豎屏YUV方向調(diào)整和圖片保存(分享)
下面小編就為大家分享一篇Android人臉識(shí)別Demo實(shí)現(xiàn)豎屏YUV方向調(diào)整和圖片保存的方法。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12Android自定義Span實(shí)現(xiàn)文字漸變效果
Android提供一些Span設(shè)置文本樣式外,開發(fā)者若希望實(shí)現(xiàn)一些新特性也是能自定義開發(fā)實(shí)現(xiàn)的。本文就將自定義Span實(shí)現(xiàn)文字漸變效果,感興趣的可以嘗試一下2022-06-06Android RxJava異步數(shù)據(jù)處理庫使用詳解
RxJava是一種異步數(shù)據(jù)處理庫,也是一種擴(kuò)展的觀察者模式。對(duì)于Android開發(fā)者來說,使用RxJava時(shí)也會(huì)搭配RxAndroid,它是RxJava針對(duì)Android平臺(tái)的一個(gè)擴(kuò)展,用于Android 開發(fā),它提供了響應(yīng)式擴(kuò)展組件,使用RxAndroid的調(diào)度器可以解決Android多線程問題2022-11-11Android實(shí)現(xiàn)屏幕旋轉(zhuǎn)方法總結(jié)
這篇文章主要介紹了Android實(shí)現(xiàn)屏幕旋轉(zhuǎn)方法,實(shí)例總結(jié)了屏幕旋轉(zhuǎn)的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04Android 創(chuàng)建依賴庫的方法(保姆級(jí)教程)
這篇文章主要介紹了Android 創(chuàng)建依賴庫的方法(保姆級(jí)教程),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01解析:繼承ViewGroup后的子類如何重寫onMeasure方法
本篇文章是對(duì)繼承ViewGroup后的子類如何重寫onMeasure方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06