共计 3901 个字符,预计需要花费 10 分钟才能阅读完成。
上篇文章,咱们曾经实现了通讯录的列表。这篇文章介绍实现通讯录右侧的索引条的性能。
显示索引条
之前咱们曾经做过了我的页面的布局,我的页面上有一个列表和一个拍照按钮,和咱们明天要实现的索引条布局非常相似。我的页面的布局如下:
通讯录界面的布局,和我的页面的布局都是应用一个 Stack 蕴含列表和其余子视图来实现。索引条是紧贴屏幕右侧,而后外面的子视图是由上至下的。所以天然的会想到应用一个 Positioned 蕴含 Column 来实现。Positioned 和 Stack 的组合咱们之前讲过,这两个组合起来应用,就和咱们 iOS 的束缚布局相似,能够设置上左宽低等等。Column 就更不必多说,咱们曾经应用过很屡次了。所以代码如下图所示:
而后优化一下索引条的地位,高度咱们设置为屏幕高度的一半,那么高低的间距就不能设置为 0 了,设置间隔上间距为屏幕的 1 / 8 看起来比拟适合。
抽取 IndexBar
首先作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这是一个我的 iOS 开发公众号:编程大鑫,不论你是小白还是大牛都欢送入驻,让咱们一起提高,独特倒退!(群内会收费提供一些群主珍藏的收费学习书籍材料以及整顿好的几百道面试题和答案文档!)
写到这里咱们会发现,这个索引条还有很多的性能须要咱们来实现,还是有点简单的,如果代码都写在 friends_page.dart 里会有点冗余,咱们齐全能够将这个索引条作为一个独立的 Widget 来实现。新建 index_bar.dart 文件,代码如下:
实现 IndexBar 的点击切换状态
当没有触摸到 IndexBar 的时候,默认是不展现背景色的,文字也是彩色的。当咱们开始点击 IndexBar 的时候,显示出背景色,而后文字也变成了红色。实现这个性能,次要是要对 GestureDetector
的两个办法有所理解。onVerticalDragDown
办法会在手指触摸 IndexBar 的时候就会被调用,onVerticalDragEnd
会在手指松开屏幕的时候调用。利用这两个办法就能够实现需求。代码如下:
因为要对文字的色彩进行批改,所以初始化 Text 的时候,就须要应用变量_textColor;
获取以后选中的下标
同样是对 GestureDetector
的一个手势办法的应用,onVerticalDragUpdate
这个办法的调用机会,在手指挪动的时候会不停的调用这个办法。这个办法有一个 DragUpdateDetails
参数,它蕴含了手指所在的坐标信息。不过是绝对于整个屏幕的坐标,能够将它转化为绝对于 IndexBar 的坐标,而后通过计算能够失去咱们以后选中的是哪个下标。代码如下:
办法中的~/ 是 flutter 特有的运算符,意思是除后取整。而 clamp()是对边界状况的解决,意思调用该函数的后果在它的两个参数之间。
回调选中的下标
这里的回调,和 OC 外面的 block,Swift 外面的闭包都是一个意思。flutter 外面带有下划线的变量是公有的,内部无法访问的。所以对外裸露的参数,不能写在 _IndexBarState
类外面,须要写在 IndexBar 类外面。申明一个闭包 (或者叫 block) 属性, 作为必传参数在初始化的时候传入。
这样,在 friends_page.dart
文件中初始化 IndexBar
的时候,就须要传入一个闭包。而后 IndexBar
外部在 onVerticalDragUpdate
的时候,调用这个闭包,就能够将以后选中的下标回调给内部了。
这个时候,会发现一个小问题,就是点击 IndexBar 的时候,回调没有执行,只有在点击并手指移动的时候才会执行。所以须要在 onVerticalDragDown
办法外面也调用一次闭包。这时候如果间接将 onVerticalDragUpdate
办法外面的代码复制到 onVerticalDragDown
办法外面的确没有问题,然而会显著的看到反复的代码太多了。
所以能够抽取一个办法,将反复的代码放到一块。
而后调用的时候就简略多了。
优化回调执行的频率
曾经胜利的实现了回调,然而从打印的后果来看,会发现同样一个下标会被回调许多次。这样咱们滚动好友列表的时候会造成不必要的性能耗费。明明只须要滚动一次,后果却滚动了无数次到同一个地位。所以这里咱们须要优化一下,一个很天然的想法就是记录一个 _currentIndexLetter
,每次执行回调的时候,判断回调的首字母是否和_currentIndexLetter
是否不同,如果是一样的就没有必要回调了,只有不同的时候,才执行回调。
代码如下:
这样回调的频率就失常了。
滚动好友列表 ListView
可滚动的 widget 都有一个 controller 属性,用于管制滚动条的行为。controller 属性是一个 ScrollController
对象。能够应用它来实现指定滚动到某个地位,实现回到顶部等性能。滚动好友列表须要一个新的对象 ScrollController
实例,将它设置给 ListView 的 controller
属性,而后就能够通过应用 ScrollController
实例来操作 ListView 的滚动。
这里临时先将滚动的偏移设置为固定值 250,试试看成果。能够看到当咱们点击 IndexBar 的时候,ListView 就会滚动到偏移为 250 的中央。接下来就是解决滚动的理论偏移值了。
滚动的理论偏移,是依据咱们的数据源来计算的。因为咱们的 cell 的高度是确定的,不显示组头的 cell 高度是 54,有组头的 cell 高度是 54 + 30 = 84。应用首字母作为 key,计算出对应的偏移为 offset,而后应用 Map(相似 iOS 中字典)记录下来。因为第一个是不是字母,而是搜寻符号,而它对应的偏移也是固定的 0。所以能够在初始化 Map 的时候就指定好。而其余的高度咱们在 initState 办法中计算。代码如下:
有了这个 Map 之后,咱们在 IndexBar 的回调办法中,就能够依据 IndexBar 回调给咱们的首字母失去对应的偏移值了。代码如下:
到这里,咱们的 IndexBar 基本上就实现了滚动 ListView 的性能。然而滚动几次之后就会发现一个小问题。。。滚动到底部的几个组头的时候,会呈现 ListView 先将组头滚动到指定地位,而后又滚回底部的状况。起因很好了解,前面的组头内容不够显示一整个屏幕了。所以咱们这里须要做下解决。这里次要是对 ListView 的滚动的监听,如果是在 iOS 中咱们会想去获取滚动视图的 contentSize 而后减去 UITableView 的高度,就是 UITableView 的最大的滚动范畴。而在 Flutter 中,这些都不须要咱们计算了。
如果须要获取到 ListView 的一些滚动相干的信息,能够将它包裹在 NotificationListener
外面,它有一个 onNotification
属性,是一个闭包,能够回调给咱们一些滚动的相干信息。蕴含在闭包参数 ScrollNotification note
外面。精确来讲滚动相干的信息蕴含在 ScrollNotification
的属性 metrics
外面。它蕴含以后滚动偏移值,能滚动的最大范畴 (这就是咱们 iOS 中 contentSize 的高减去 UITableView 的高) 等等信息。残缺代码如下:
将 _maxScrollExtent
定义为一个属性就好了。须要留神的是并不能给初始值为 0,否则没有滚动 ListView 之前,应用 IndexBar 就无奈滚动 ListView 了。
至此,IndexBar 滚动 ListView 的性能就实现了。
显示指示器
终于来到了最初一步,显示咱们 IndexBar 的指示器。首先思考的就是布局。最后的 IndexBar 只有右侧的下标一列。当初咱们左侧须要一块容器用来显示咱们的指示器,所以 IndexBar 的根视图应该思考改为 Row。指示器背景的不规则图形能够应用一张图片展现,图片曾经筹备好了。两头的文字,应用 Text 就够了。先看下大略布局代码:
如果感觉地位不是很适合,能够批改一下各自的宽度。而后是对指示器的显示与暗藏做管制,指示器的显示与暗藏的管制,应该说跟背景色的显示暗藏是相似的。都是在手势的那两个办法外面实现管制。应用一个 bool 变量来管制指示器的显示与暗藏,在手势的触摸办法和来到办法外面操作这个 bool 变量,而后 setState()就能够实现了指示器的显示与暗藏了。而后是对于指示器的显示文本的。这个文本就是咱们的 _currentIndexLetter
,间接应用就好了。最初是对于如何管制整个 IndexBar 的高低位移的。通过对 Alignment 的应用,发现能够管制 IndexBar 的高低位移。通过一直的批改 Alignment 的 y 值会找到一个适合的 y 值指向第一个放大镜,那么 - y 就指向最初一个字母 Z。我这里试了几次发现 y =-1.13 的时候,指示器刚刚好指向第一个放大镜的地位。那么当初的问题就是将 1.13 * 2 = 2.26 分成_index_words.length - 1
份,而后依据抉择的下标,获得对应的 Alignment 的 y 值。当咱们抉择第一个的时候下标为 0,y 值应该为 -1.13, 当咱们抉择最初一个的时候下标为 _index_words.length - 1
,y 值应该为 1.13。依据这些信息就能够找到计算 y 值的公式。最终的代码如下:
新增两个变量 _showIndicator
和_indicatorAlignmentY
。
应用这两个变量还有_currentIndexLetter
到这里,咱们就终于实现了通讯录的 IndexBar 的封装。下一节会介绍一些网络申请了 …
本次分享就到这了,感激观看!