8天讓iOS開發者上手Flutter之五

上篇文章,咱們已經完成了通信錄的列表。這篇文章介紹完成通信錄右側的索引條的功能。markdown

顯示索引條

以前咱們已經作過了個人頁面的佈局,個人頁面上有一個列表和一個拍照按鈕,和咱們今天要實現的索引條佈局十分相似。個人頁面的佈局以下: image.png 通信錄界面的佈局,和個人頁面的佈局都是使用一個Stack包含列表和其餘子視圖來實現。索引條是緊貼屏幕右側,而後裏面的子視圖是由上至下的。因此天然的會想到使用一個Positioned包含Column來實現。Positioned和Stack的組合咱們以前講過,這兩個組合起來使用,就和咱們iOS的約束佈局相似,能夠設置上左寬高等等。Column就更不用多說,咱們已經使用過不少次了。因此代碼以下圖所示: image.png網絡

而後優化一下索引條的位置,高度咱們設置爲屏幕高度的一半,那麼上下的間距就不能設置爲0了,設置距離上間距爲屏幕的1/8看起來比較合適。

image.png

抽取IndexBar

寫到這裏咱們會發現,這個索引條還有不少的功能須要咱們來實現,仍是有點複雜的,若是代碼都寫在friends_page.dart裏會有點冗餘,咱們徹底能夠將這個索引條做爲一個獨立的Widget來實現。新建index_bar.dart文件,代碼以下: image.png閉包

實現IndexBar的點擊切換狀態

當沒有觸摸到IndexBar的時候,默認是不展現背景色的,文字也是黑色的。當咱們開始點擊IndexBar的時候,顯示出背景色,而後文字也變成了白色。 實現這個功能,主要是要對GestureDetector的兩個方法有所瞭解。onVerticalDragDown方法會在手指觸摸IndexBar的時候就會被調用,onVerticalDragEnd會在手指鬆開屏幕的時候調用。利用這兩個方法就能夠實現需求。代碼以下: image.png 由於要對文字的顏色進行修改,因此初始化Text的時候,就須要使用變量_textColor; image.png函數

獲取當前選中的下標

一樣是對GestureDetector的一個手勢方法的使用,onVerticalDragUpdate這個方法的調用時機,在手指移動的時候會不停的調用這個方法。這個方法有一個DragUpdateDetails參數,它包含了手指所在的座標信息。不過是相對於整個屏幕的座標,能夠將它轉化爲相對於IndexBar的座標,而後經過計算能夠獲得咱們當前選中的是哪一個下標。代碼以下: image.png 方法中的~/是flutter特有的運算符,意思是除後取整。而clamp()是對邊界狀況的處理,意思調用該函數的結果在它的兩個參數之間。佈局

回調選中的下標

這裏的回調,和OC裏面的block,Swift裏面的閉包都是一個意思。flutter裏面帶有下劃線的變量是私有的,外部沒法訪問的。因此對外暴露的參數,不能寫在_IndexBarState類裏面,須要寫在IndexBar類裏面。聲明一個閉包(或者叫block)屬性,做爲必傳參數在初始化的時候傳入。 image.png 這樣,在friends_page.dart文件中初始化IndexBar的時候,就須要傳入一個閉包。而後IndexBar內部在onVerticalDragUpdate的時候,調用這個閉包,就能夠將當前選中的下標回調給外部了。 image.png image.png 這個時候,會發現一個小問題,就是點擊IndexBar的時候,回調沒有執行,只有在點擊並手指挪動的時候纔會執行。因此須要在onVerticalDragDown方法裏面也調用一次閉包。這時候若是直接將onVerticalDragUpdate方法裏面的代碼複製到onVerticalDragDown方法裏面確實沒有問題,可是會明顯的看到重複的代碼太多了。 image.png 因此能夠抽取一個方法,將重複的代碼放到一塊。 image.png 而後調用的時候就簡單多了。 image.png性能

優化回調執行的頻率

已經成功的實現了回調,可是從打印的結果來看,會發現一樣一個下標會被回調許屢次。這樣咱們滾動好友列表的時候會形成沒必要要的性能消耗。明明只須要滾動一次,結果卻滾動了無數次到同一個位置。因此這裏咱們須要優化一下,一個很天然的想法就是記錄一個_currentIndexLetter,每次執行回調的時候,判斷回調的首字母是否和_currentIndexLetter是否不一樣,若是是同樣的就沒有必要回調了,只有不一樣的時候,才執行回調。 image.png 代碼以下: image.png image.png 這樣回調的頻率就正常了。優化

滾動好友列表ListView

可滾動的widget都有一個controller屬性,用於控制滾動條的行爲。controller屬性是一個ScrollController對象。可使用它來實現指定滾動到某個位置,實現回到頂部等功能。 滾動好友列表須要一個新的對象ScrollController實例,將它設置給ListView的controller屬性,而後就能夠經過使用ScrollController實例來操做ListView的滾動。 image.png image.png 這裏暫時先將滾動的偏移設置爲固定值250,試試看效果。能夠看到當咱們點擊IndexBar的時候,ListView就會滾動到偏移爲250的地方。接下來就是處理滾動的實際偏移值了。spa

滾動的實際偏移,是根據咱們的數據源來計算的。由於咱們的cell的高度是肯定的,不顯示組頭的cell高度是54,有組頭的cell高度是54 + 30 = 84。使用首字母做爲key,計算出對應的偏移爲offset,而後使用Map(相似iOS中字典)記錄下來。因爲第一個是否是字母,而是搜索符號,而它對應的偏移也是固定的0。因此能夠在初始化Map的時候就指定好。而其餘的高度咱們在initState方法中計算。代碼以下: image.png3d

有了這個Map以後,咱們在IndexBar的回調方法中,就能夠根據IndexBar回調給咱們的首字母獲得對應的偏移值了。代碼以下: image.pngcode

到這裏,咱們的IndexBar基本上就實現了滾動ListView的功能。可是滾動幾回以後就會發現一個小問題。。。滾動到底部的幾個組頭的時候,會出現ListView先將組頭滾動到指定位置,而後又滾回底部的狀況。緣由很好理解,後面的組頭內容不夠顯示一整個屏幕了。因此咱們這裏須要作下處理。這裏主要是對ListView的滾動的監聽,若是是在iOS中咱們會想去獲取滾動視圖的contentSize而後減去UITableView的高度,就是UITableView的最大的滾動範圍。而在Flutter中,這些都不須要咱們計算了。

若是須要獲取到ListView的一些滾動相關的信息,能夠將它包裹在NotificationListener裏面,它有一個onNotification屬性,是一個閉包,能夠回調給咱們一些滾動的相關信息。包含在閉包參數ScrollNotification note裏面。準確來說滾動相關的信息包含在ScrollNotification的屬性metrics裏面。它包含當前滾動偏移值,能滾動的最大範圍(這就是咱們iOS中contentSize的高減去UITableView的高)等等信息。完整代碼以下: image.png_maxScrollExtent定義爲一個屬性就行了。須要注意的是並不能給初始值爲0,不然沒有滾動ListView以前,使用IndexBar就沒法滾動ListView了。 image.png 至此,IndexBar滾動ListView的功能就實現了。

顯示指示器

終於來到了最後一步,顯示咱們IndexBar的指示器。首先考慮的就是佈局。最初的IndexBar只有右側的下標一列。如今咱們左側須要一塊容器用來顯示咱們的指示器,因此IndexBar的根視圖應該考慮改成Row。指示器背景的不規則圖形可使用一張圖片展現,圖片已經準備好了。中間的文字,使用Text就夠了。先看下大概佈局代碼: image.png

若是以爲位置不是很合適,能夠修改一下各自的寬度。而後是對指示器的顯示與隱藏作控制,指示器的顯示與隱藏的控制,應該說跟背景色的顯示隱藏是相似的。都是在手勢的那兩個方法裏面實現控制。使用一個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_indicatorAlignmentYimage.png 使用這兩個變量還有_currentIndexLetter image.png

到這裏,咱們就終於實現了通信錄的IndexBar的封裝。下一節會介紹一些網絡請求了...

相關文章
相關標籤/搜索