日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Flutter仿写一个iOS风格的通讯录

發布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Flutter仿写一个iOS风格的通讯录 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

此文章主要介紹怎么使用Flutter的Cupertino風格控件,寫一個iOS風格的通訊錄,還有在此過程中遇到的問題及解決辦法。

大家在用Flutter寫App的時候,一般都會使用material風格的控件,因為material風格的控件比較豐富,但是,他在iOS上就會顯得Android氣息比較重,不太適合,所以本文章將通過用仿寫iOS通訊錄,系統地介紹Cupertino控件,及系統的一些底層控件和怎么自己定義優美的適合自己的控件。

由于使用的聯系人三方包的限制,有些功能未能實現,我會持續關注這個聯系人插件的更新,及時加上新功能。

Github地址

首頁

主要用到的控件及問題

CupertinoPageScaffold

一個iOS風格Scaffold,可以添加NavigationBar。

NestedScrollView

實現浮動的NavigationBar和SearchBar。

NestedScrollView我用的自己重寫過的,主要是因為源碼中的有兩個問題。

1、當列表滑動到底部,然后繼續滑動,然后停止,松手,這時候可列表會重新滾動到底部,但是源碼沒有處理當速度等于0的時候的情況,所以當松手的時候,列表會回彈回去,回彈距離小于maxScrollExtent。

源碼如下:

@protected ScrollActivity createInnerBallisticScrollActivity(_NestedScrollPosition position, double velocity) {return position.createBallisticScrollActivity(position.physics.createBallisticSimulation(velocity == 0 ? position as ScrollMetrics : _getMetrics(position, velocity),velocity,),mode: _NestedBallisticScrollActivityMode.inner,); }

這里當velocity == 0的時候,直接把innerPosition賦值給了createBallisticSimulation方法的position參數,我們繼續往下看。

ScrollActivity createBallisticScrollActivity(Simulation simulation, {@required _NestedBallisticScrollActivityMode mode,_NestedScrollMetrics metrics, }) {if (simulation == null) return IdleScrollActivity(this);assert(mode != null);switch (mode) {case _NestedBallisticScrollActivityMode.outer:assert(metrics != null);if (metrics.minRange == metrics.maxRange) return IdleScrollActivity(this);return _NestedOuterBallisticScrollActivity(coordinator,this,metrics,simulation,context.vsync,);case _NestedBallisticScrollActivityMode.inner:return _NestedInnerBallisticScrollActivity(coordinator,this,simulation,context.vsync,);case _NestedBallisticScrollActivityMode.independent:return BallisticScrollActivity(this, simulation, context.vsync);}return null; }

這里velocity == 0的時候,執行的是

case _NestedBallisticScrollActivityMode.inner:return _NestedInnerBallisticScrollActivity(coordinator,this,simulation,context.vsync,);

這時候的simulation就是上面通過innerPosition得到的,然后傳給了_NestedInnerBallisticScrollActivity,我們在繼續往下看,

class _NestedInnerBallisticScrollActivity extends BallisticScrollActivity {_NestedInnerBallisticScrollActivity(this.coordinator,_NestedScrollPosition position,Simulation simulation,TickerProvider vsync,) : super(position, simulation, vsync);final _NestedScrollCoordinator coordinator;@override_NestedScrollPosition get delegate => super.delegate as _NestedScrollPosition;@overridevoid resetActivity() {delegate.beginActivity(coordinator.createInnerBallisticScrollActivity(delegate,velocity,));}@overridevoid applyNewDimensions() {delegate.beginActivity(coordinator.createInnerBallisticScrollActivity(delegate,velocity,));}@overridebool applyMoveTo(double value) {return super.applyMoveTo(coordinator.nestOffset(value, delegate));} }

我們發現這里執行的操作并不是我們想要的,當velocity == 0,滑動距離大于maxScrollExtent的時候,我們只想滾動到列表的最底部,所以我們改一下這里的實現。此處有兩種實現方式:

第一種方式:改_getMetrics方法
// This handles going forward (fling up) and inner list is // underscrolled, OR, going backward (fling down) and inner list is // scrolled past zero. We want to skip the pixels we don't need to grow // or shrink over. if (velocity > 0.0) {// shrinkingextra = _outerPosition.minScrollExtent - _outerPosition.pixels; } else if (velocity < 0.0) {// growingextra = _outerPosition.pixels - (_outerPosition.maxScrollExtent - _outerPosition.minScrollExtent); } else {extra = 0.0; } assert(extra <= 0.0); minRange = _outerPosition.minScrollExtent; maxRange = _outerPosition.maxScrollExtent + extra; assert(minRange <= maxRange); correctionOffset = 0.0;

這里加上velocity == 0的判斷。

第二種方式:修改createInnerBallisticScrollActivity方法,加上velocity == 0的判斷。
@protected ScrollActivity createInnerBallisticScrollActivity(_NestedScrollPosition position, double velocity) {return position.createBallisticScrollActivity(position.physics.createBallisticSimulation(velocity == 0 ? position as ScrollMetrics : _getMetrics(position, velocity),velocity,),mode: velocity == 0 ? _NestedBallisticScrollActivityMode.independent : _NestedBallisticScrollActivityMode.inner,); }

2、當我們手動調用position.moveTo方法滾動到最底部的時候,獲取到的maxScrollExtent并不是實際innerPosition的maxScrollExtent,而應該是maxScrollExtent - outerPosition.maxScrollExtent + outerPosition.pixels。

接下來我們分析源碼看看哪里出了問題。
首先,我們看看與之有直接關聯的maxScrollExtent方法。

@override double get maxScrollExtent => _maxScrollExtent;

我們看到只是單純的返_maxScrollExtent,那我們看看_maxScrollExtent是在哪里賦值的,經過查看源碼得知,_maxScrollExtent賦值的地方主要在下面這個方法里:

@override bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) {assert(minScrollExtent != null);assert(maxScrollExtent != null);if (!nearEqual(_minScrollExtent, minScrollExtent, Tolerance.defaultTolerance.distance) ||!nearEqual(_maxScrollExtent, maxScrollExtent, Tolerance.defaultTolerance.distance) ||_didChangeViewportDimensionOrReceiveCorrection) {assert(minScrollExtent != null);assert(maxScrollExtent != null);assert(minScrollExtent <= maxScrollExtent);_minScrollExtent = minScrollExtent;_maxScrollExtent = maxScrollExtent;_haveDimensions = true;applyNewDimensions();_didChangeViewportDimensionOrReceiveCorrection = false;}return true; }

所以我們重寫這個方法,修改如下:

@override bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) {assert(minScrollExtent != null);assert(maxScrollExtent != null);var outerPosition = coordinator._outerPosition;var outerMaxScrollExtent = outerPosition.maxScrollExtent;var outerPixels = outerPosition.pixels;if (outerMaxScrollExtent != null && outerPixels != null) {maxScrollExtent -= outerMaxScrollExtent - outerPixels;maxScrollExtent = math.max(minScrollExtent, maxScrollExtent);}return super.applyContentDimensions(minScrollExtent, maxScrollExtent); }

這樣我們成功解決了上面提到的兩個問題。

CustomScrollView

實現浮動的Index。

SliverPersistentHeader

實現Index固定在頭部。

CupertinoSliverRefreshIndicator

實現下拉刷新。

群組

新建聯系人頁面

編輯頭像

聯系人詳情

選擇標簽

至此,基本完成。

總結

以上是生活随笔為你收集整理的Flutter仿写一个iOS风格的通讯录的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。