【Flutter】微信项目实战【07】 通讯录界面搭建(下)

2,267 阅读5分钟

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

📝【Flutter】学习养成记,【程序员必备技能】

📔【Flutter】微信项目实战!

1. 写在前面

上篇文章中已经对微信通讯录界面进行了列表部分,包括组头的设置、怎么显示隐藏合并组的代码实现,那么今天就继续来写微信实战项目的通讯录界面最复杂的索引条部分!

最终效果.gif

2. 页面布局

首先索引条是在列表之上的,也就是布局来说是悬浮的,那么我们可以使用Stack 来布局,然后在封装一个索引条IndexBar

通讯录布局

3. 索引条封装

索引条是需要改变状态的,索引我们使用StatefulWidget,方便后续的状态的改变,以根据状态的改变来改变列表的显示。索引是由两部分组成的:

  • 指示器:就是拖动索引条,前面的放大器部分,里面显示对应的索引字母。
  • 索引条:显示分组的名称字母,这个要根据鼠标的移动,来改变指示器的位置和显示的文字。

大致的代码布局如下所示:

索引条代码结构

索引条是悬浮的,所以需要定位它的位置,这里使用Positioned来定位。这里设置索引条的高度是屏幕高的一半,距离屏幕的顶部距离是屏幕高度的八分之一,宽度为 120。

索引条

3.1 指示器

指示器这里和索引条是一体的,只是改变一下位置就可以了。

//指示器
          Container(
            alignment: Alignment(0,_indicatorY),
            width: 100,
            // color: Colors.red,
            child: _indicatorHidden?null:Stack(
              alignment: const Alignment(-0.2,0),
              children: [
               const Image(image: AssetImage("images/气泡.png"),width: 60,),
                Text(_indicatorText,style: const TextStyle(fontSize: 18,color: Colors.white),)
              ],
            ),
          ),

这里指示器外面是用Container包裹,里面是使用了Stack来包裹一个放大镜🔍的图片,再把需要显示的Text置顶,以此来达到我们需要的效果。 字母索引我们这里是使用一个 List,遍历本地写的一个字母 LIst 来参加字母的 widget,具体代码如下所示:

在这里插入图片描述

3.2 索引条

索引条是需要响应手势的,所以用GestureDetector来包裹起来。

针对鼠标的拖动时、离开时的回调方法来处理不同的状态。

我们要定位索引条字母的位置,根据鼠标移动的位置来改变,指示器的移动位置,这就得拿到坐标才可以。系统还真提供了这样一个方法,可以通过RenderBox来找到当前的位置。获取的代码如下所示:

int getIndexItem(BuildContext context,Offset globalPosition){
  //拿到当前盒子
  RenderBox box = context.findRenderObject() as RenderBox;
  //拿到y值,当前位置到部件原点(部件左上角)的距离(x,y)
  var y = box.globalToLocal(globalPosition).dy;
  //算出字符高度
  var itemHeight = screenHeight(context)/2/INDEX_WORDS.length;
  int index = y ~/itemHeight.clamp(0, INDEX_WORDS.length-1);//~取整,设置取整范围clamp
  print("${INDEX_WORDS[index]}");
  return index;
}

这里封装了一个方法,来获取每个字母的位置,然后在数据移动的相关回调方法里面直接调用就可以了。具体的处理逻辑如下图所示:

字母索引

那么现在我们来看看,鼠标移动是否可以达到改变指示器的效果呢?

索引条

从上面的效果图来看,已经基本满足了我们的需求,现在还有一个功能需要实现,就是点击索引对应的字母,让列表滚动起来,而且滚动的效果是,我点击那个字母,所在组就置顶。那么现在就去实现一下吧!

3.3 列表置顶

那么实现的思路,就是我们得知道整个列表对应的字母的偏移量,根据对应字母的偏移量来对列表进行偏移就可以了。那么该如何去计算这个偏移量呢?计算的时机是在什么时候呢?

我们肯定不能动态的去计算吧,不能你点击一次就计算一下,应该是界面进来的时候就是已经计算好了的。

final Map _groupOffsetMap = {
    INDEX_WORDS[0]:0.0,
    INDEX_WORDS[0]:0.0,
  };

我们这里使用一个字典也就是 Map来存放对应字母的偏移量,在处理组头的时候就顺便一起计算,存在map 里面,这样我点击的是那个字母或者鼠标滚动到对应的字母,就改变偏移量就 OK 了!

//索引条
          IndexBar(indexBarCallBack:(String str){
            if(_groupOffsetMap[str]!=null){

              _scrollController.animateTo(_groupOffsetMap[str],
                  duration: const Duration(microseconds: 100),
                  curve: Curves.easeIn);
            }

          }
          ),

这里IndexBar的回调方法indexBarCallBack,在其回调方法里面对字典里面的对应字母值进行判断,然后控制器去控制对应的偏移量。完成效果如下:

索引条效果

以上就是本次博客的全部内容,欢迎大家留言交流。更详细的代码请移步这里👉GitHub项目地址

4. 写在后面

  • 基础语法合集

【Flutter】Dart中的var、final 和 const基本使用

【Flutter】Dart数据类型之num

【Flutter】Dart数据类型之String

【Flutter】Dart的数据类型list&Map(数组和字典)

【Flutter】Dart的方法与箭头函数

【Flutter】Dart的方法中的可选参数、方法作为参数传递

【Flutter】Dart中的匿名函数、闭包

【Flutter】Dart中的类和对象

【Flutter】Dart中的构造函数

【Flutter】Dart的工厂构造方法&单例对象&初始化列表

【Flutter】Dart的类方法和对象操作符

【Flutter】Dart中的继承

【Flutter】Dart中的抽象类和接口

【Flutter】Dart中的Mixins混入你知道是什么吗?

  • [基础组件合集]

【Flutter】基础组件【01】Text

【Flutter】基础组件【02】Container

【Flutter】基础组件【03】Scaffold

【Flutter】基础组件【04】Row/Column

【Flutter】基础组件【05】Image

【Flutter】基础组件【06】Icon

【Flutter】基础组件【07】Appbar

【Flutter】基础组件【08】BottomNavigationBar

【Flutter】基础组件【09】Button

  • [项目实战合集]

【Flutter】微信项目实战【01】基本框架搭建

【Flutter】微信项目实战【02】我的界面搭建(上)

【Flutter】微信项目实战【03】我的界面搭建(下)

【Flutter】微信项目实战【04】发现界面搭建

【Flutter】微信项目实战【05】 通讯录界面搭建(上)

【Flutter】微信项目实战【06】 通讯录界面搭建(中)

GitHub项目地址

关注我,更多内容持续输出

🌹 喜欢就点个赞吧👍🌹

🌹 觉得有收获的,可以来一波 收藏+关注,以免你下次找不到我😁🌹

🌹欢迎大家留言交流,批评指正,转发请注明出处,谢谢支持!🌹