千家信息网

Flutter仿微信通讯录怎么实现自定义导航条

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,这篇文章主要介绍了Flutter仿微信通讯录怎么实现自定义导航条的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Flutter仿微信通讯录怎么实现自定义导航条文章都会有所收
千家信息网最后更新 2025年02月01日Flutter仿微信通讯录怎么实现自定义导航条

这篇文章主要介绍了Flutter仿微信通讯录怎么实现自定义导航条的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Flutter仿微信通讯录怎么实现自定义导航条文章都会有所收获,下面我们一起来看看吧。

关键点:手势定位滑动、列表定位、手势、列表联动。

准备数据,首先我们需要准备导航目录数据,

List _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", ];

然后列表数据,列表数据可以让后台给我们排序好,如果后台不给我们排序,我们也可以自己排序进行组装, 这里用到一个插件,根据汉字获取拼音首字母,我们自己就可以对这些数据进行整理排序。

lpinyin: ^2.0.3

数据格式:一个NameBean对应一个字母所在的列表,这是我们存储正式列表数据的格式。

class NameBean {  String? initial;// 字母导航  List? nameList;// 内容列表  NameBean({    this.initial,    this.nameList,  });}/// name : "老李"/// 这里我只放了一个name字段,以后扩展内容只需在这里新增字段就好了class Name {  String? name;  Name({    this.name,  });}

接下来我们先做导航条:

实现思路: 导航条就是一个List列表,点击、滑动、松开会有不同的交互,我们根据不同的交互来进行实现,这里我们会用到官方的GestureDetector组件,专门用来进行手势识别。将每一个item的高度固定,通过手势交互返回的位置数据来进行返回我们想要的目录。比如我的每一个目录高度设置为20.

导航条代码:点击或者移动的时候选中的目录会有一个按压效果,

GestureDetector(  child: Container(      margin: EdgeInsetsDirectional.only(top: 40),      width: 40,      // 导航条      child: ListView.builder(        physics: NeverScrollableScrollPhysics(),        shrinkWrap: true,        itemBuilder: (context, index) {          return SizedBox(            height: 20,            // 这里做了一个按压或移动滑动的触发效果            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,      )),      //手指按下触发 竖着划就用onVertica XXX回调  onVerticalDragDown: (DragDownDetails e) {    //打印手指按下的位置(相对于屏幕)    int i = e.localPosition.dy ~/ 20;    // _scrollController.jumpTo(index: i);    setState(() {      currentIndex = i;    });  },  //手指滑动时会触发此回调  onVerticalDragUpdate: (DragUpdateDetails e) {    //用户手指滑动时,更新偏移    int i = e.localPosition.dy ~/ 20;    _az.length;    if (i >= 0 && i <= _az.length - 1) {      if (i != currentIndex) {        setState(() {        // 当前选中的index 默认-1          currentIndex = i;        });        print("滑动 ${_az[i]}");                    }    }  },  // 手指抬起  onTapUp: (e) {    // 手指抬起    setState(() {      currentIndex = -1;    });  },  // 移动取消  onVerticalDragEnd: (e) {    // 移动取消    setState(() {      currentIndex = -1;    });  },)

然后我们可以看到微信在滑动的时候有个字母放大气泡会跟随着手势移动。

实现思路:

气泡和导航条并列,并根据手势位置更新上边距即可,因为我们的导航条的每一个item的高度是固定的,所以我们就可以根据滑动的位置计算出滑动距离顶部的高度,这里气泡可以让UI切个背景图,也可以自己用canvas画一个。

气泡绘制源码:

@overridevoid paint(Canvas canvas, Size size) {  // 原点移到左下角  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));}

导航条、气泡都完成了,接下来就非常简单了,内容的填充我们就不能用ListView了,这里我们需要一个官方的插件: scrollable_positioned_list: ^0.2.3 使用它可以定位到具体的item位置,这样我们就可以进行列表定位和导航条进行联动了。

内容代码:

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(            // 禁用滑动事件            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一直,只是它多了一个这个方法,可以定位到具体的item。

_scrollController.jumpTo(index: i);

看下最终效果:

关于"Flutter仿微信通讯录怎么实现自定义导航条"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"Flutter仿微信通讯录怎么实现自定义导航条"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。

0