Flutter仿微信通訊錄實(shí)現(xiàn)自定義導(dǎo)航條的示例代碼
某些頁(yè)面比如我們?cè)谶x擇聯(lián)系人或者某個(gè)城市的時(shí)候需要快速定位到我們需要的選項(xiàng),一般都會(huì)需要像微信通訊錄右邊有一個(gè)導(dǎo)航條一樣的功能,由A到Z進(jìn)行快速定位,本篇文章我們將自己來(lái)實(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,
});
}接下來(lái)我們先做導(dǎo)航條:
實(shí)現(xiàn)思路: 導(dǎo)航條就是一個(gè)List列表,點(diǎn)擊、滑動(dòng)、松開(kāi)會(huì)有不同的交互,我們根據(jù)不同的交互來(lái)進(jìn)行實(shí)現(xiàn),這里我們會(huì)用到官方的GestureDetector組件,專門(mén)用來(lái)進(jìn)行手勢(shì)識(shí)別。將每一個(gè)item的高度固定,通過(guò)手勢(shì)交互返回的位置數(shù)據(jù)來(lái)進(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畫(huà)一個(gè)。
氣泡繪制源碼:目前我在學(xué)習(xí)繪制組件,順便畫(huà)了一個(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)航條、氣泡都完成了,接下來(lái)就非常簡(jiǎn)單了,內(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é):
通過(guò)這個(gè)組件我們可以簡(jiǎn)單的了解Flutter的手勢(shì)交互操作,通過(guò)手勢(shì)識(shí)別我們可以實(shí)現(xiàn)很多有意思的組件,尤其結(jié)合繪制和動(dòng)畫(huà)可以做出來(lái)非常有意思的交互,所有的交互最終的底層都是通過(guò)手勢(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 app判斷是否有系統(tǒng)簽名步驟詳解
這篇文章主要為大家介紹了android app判斷是否有系統(tǒng)簽名步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
Android 關(guān)于“NetworkOnMainThreadException”問(wèn)題的原因分析及解決辦法
這篇文章主要介紹了Android 關(guān)于“NetworkOnMainThreadException”的相關(guān)知識(shí),本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-02-02
Android?Hilt?Retrofit?Paging3使用實(shí)例
這篇文章主要介紹了Android?Hilt依賴注入的使用,首先,某個(gè)類的成員變量稱為依賴,如若此變量想要實(shí)例化引用其類的方法,可以通過(guò)構(gòu)造函數(shù)傳參或者通過(guò)某個(gè)方法獲取對(duì)象,此等通過(guò)外部方法獲取對(duì)象實(shí)例的稱為依賴注入2023-01-01
android串口開(kāi)發(fā)入門(mén)之搭建ndk開(kāi)發(fā)環(huán)境及第一個(gè)jni調(diào)用程序
這篇文章主要給大家介紹了關(guān)于android串口開(kāi)發(fā)入門(mén)之搭建ndk開(kāi)發(fā)環(huán)境及第一個(gè)jni調(diào)用程序的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01
Android Activity與Fragment實(shí)現(xiàn)底部導(dǎo)航器
這篇文章主要介紹了Android Activity與Fragment實(shí)現(xiàn)底部導(dǎo)航器的相關(guān)資料,并附實(shí)例代碼,需要的朋友可以參考下2016-11-11
Android自定義VIew實(shí)現(xiàn)衛(wèi)星菜單效果淺析
這篇文章主要介紹了Android自定義VIew實(shí)現(xiàn)衛(wèi)星菜單效果淺析,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11
Android實(shí)現(xiàn)左右滑動(dòng)效果的方法詳解
本篇文章是對(duì)Android實(shí)現(xiàn)左右滑動(dòng)效果的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
深入android中The connection to adb is
本篇文章是對(duì)android中The connection to adb is down的問(wèn)題以及解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05

