上篇文章,咱们曾经实现了通讯录的列表。这篇文章介绍实现通讯录右侧的索引条的性能。
显示索引条
之前咱们曾经做过了我的页面的布局,我的页面上有一个列表和一个拍照按钮,和咱们明天要实现的索引条布局非常相似。我的页面的布局如下:
通讯录界面的布局,和我的页面的布局都是应用一个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的封装。下一节会介绍一些网络申请了...
本次分享就到这了,感激观看!