您好,登錄后才能下訂單哦!
這篇文章主要講解了如何實現flutter仿微信底部圖標漸變功能,內容清晰明了,對此有興趣的小伙伴可以學習一下,相信大家閱讀完之后會有幫助。
先給大家展示下效果圖,感覺不錯請參考實例代碼。
實現思路
在flutter中,如果想實現上面的頁面切換效果,必然會想到pageView。pageView的controller可以監聽到pageView的滾動事件,也可以獲取pageView滾動的位置,所以我們在滾動事件中根據位置去改變對應的圖標顏色就可以實現了。
改變圖標顏色
圖標是從微信中提取出來的,都是webp格式的圖片。要改變圖片顏色可以使用ImageIcon這個組件。
ImageIcon會把一張圖片變成單色圖片,所以只要圖片沒有多色的要求,就可以用這個組件。
既然能改變顏色了,我們也需要知道pageView滾動的時候究竟要改什么顏色。從一個頁面滾動到另一個頁面的過程中,顏色都是線性漸變的,要獲取這個過程中的顏色可以使用flutter的Color類提供的lerp方法,作用是獲取兩種顏色之間的線性差值
里面有3個參數,a和b都是顏色,t是夾在0到1之間的,當t為0時返回a,當t為1時返回b
也就是在滾動事件中,計算出 t ,根據 t 改變圖標顏色就可以實現上面的效果了。
pageController.addListener(() { int currentPage = pageController.page.toInt(); //當前頁面的page是double類型的, 把它減去當前頁面的int類型就可以得出當前頁面到下一個頁面的偏移量了 double t = pageController.page - currentPage; //根據上一次的頁面位置獲得方向 if (lastPage <= pageController.page) { //向右滑動時currentPage是當前頁 //從當前頁過渡到下一頁 streamController.sink.add(StreamModel( timeline: t, index: currentPage, gotoIndex: currentPage + 1)); } else { //向左滑動時currentPage是上一頁 //從當前頁過渡到上一頁 streamController.sink.add(StreamModel( timeline: t, index: currentPage + 1, gotoIndex: currentPage)); } lastPage = pageController.page; });
上面代碼中currentPage的值舉個例子:當前page是1,要滑動到2,那么它的值是1.11...1.21...這樣一直到2,所以在這個過程中currentPage是當前頁。如果當前page是4,要滑動到3的時候,它的值是3.99...3.81...這樣一直到3,在這個過程中currentPage就是上一頁了。
t 的計算就更簡單了,1.11-1=0.11,3.99-3=0.99 .....
管理圖標顏色
因為我是用了自帶的底部導航BottomNavigationBar,在pageController的滾動事件中改變圖標顏色太麻煩了,所以用了Stream來管理圖標的狀態。使用Stream創建一個多訂閱的管道,讓所有圖標都訂閱它,然后在滑動事件中把需要的數據都發送給所有圖標。
需要的數據:
class StreamModel { const StreamModel({this.timeline, this.index, this.gotoIndex}); final double timeline; final int index; final int gotoIndex; }
圖標組件
構造方法設置一個index,方便判斷圖標是哪個。
使用StreamBuilder包住要改變顏色的組件,并且綁定從構造函數設置的StreamController。
在StreamBuilder中根據pageView滾動事件傳進來的參數控制圖標顏色。
class BottomNavIcon extends StatelessWidget { final StreamController<StreamModel> streamController; final int index; final String img; final String title; final double fontSize; Color _color; Color _activeColor; final bool isActive; BottomNavIcon(this.title, this.img, this.index, {@required this.streamController, this.isActive = false, this.fontSize = 18.0, Color color = Colors.grey, Color activeColor = Colors.blue}) { _color = isActive ? activeColor : color; _activeColor = isActive ? color : activeColor; } @override Widget build(BuildContext context) { return StreamBuilder( stream: streamController.stream, builder: (BuildContext context, AsyncSnapshot snapshot) { final StreamModel data = snapshot.data; double t = 0.0; if (data != null) { //開始的index if (data.index == index) { t = data.index > data.gotoIndex ? data.timeline : 1.0 - data.timeline; print("this${data.index}:${t}"); } //結束的index if (data.gotoIndex == index) { t = data.index > data.gotoIndex ? 1.0 - data.timeline //開始的index大于結束的index方向向左 : data.timeline; //小于方向向右 //過渡到的圖標顏色的插值超過0.6時, 個人感覺當前顏色和結束的哪個顏色相差太多, //所以超過0.6時恢復默認顏色 t = t >= 0.6 ? 1 : t; print("goto${data.gotoIndex}:${t}"); } } if (t > 0.0 && t < 1.0) { //color.lerp 獲取兩種顏色之間的線性插值 return Column( children: <Widget>[ ImageIcon(AssetImage(this.img), color: Color.lerp(_color, _activeColor, t)), Text(title, style: TextStyle( fontSize: fontSize, color: Color.lerp(_color, _activeColor, t))), ], ); } return Column( children: <Widget>[ ImageIcon(AssetImage(this.img), color: Color.fromRGBO(_color.red, _color.green, _color.blue, 1)), Text(title, style: TextStyle( fontSize: fontSize, color: Color.fromRGBO( _color.red, _color.green, _color.blue, 1))), ], ); }); } }
圖標的顏色都是當前的(index == data.index)漸漸變淺,要滾動到(index==data.gotoIndex)的圖標顏色漸深
創建多訂閱的管道(Stream)
final StreamController<StreamModel> streamController = StreamController.broadcast(); 加載圖標 for (int i = 0; i < pages.length; i++) { TabBarModel model = pages[i]; bars.add( BottomNavigationBarItem( icon: BottomNavIcon( model.title, 'assets/images/tabbar_' + model.icon + '_c.webp', i, streamController: streamController, ), activeIcon: BottomNavIcon( model.title, 'assets/images/tabbar_' + model.icon + '_s.webp', i, streamController: streamController, isActive: true, ), title: Center(), ), ); }
上面代碼的title為Center的原因是已經在圖標組件中創建了一個顯示標題的組件,方便一起設置顏色。這里就不需要了,但是它的title不允許為null,所以隨便給它一個高寬都是0的組件
結語
其實這個效果和微信的不是一模一樣,微信的應該是選中圖標疊加到默認圖標上面。默認圖標顏色線性漸變,選中圖標透明度漸變。flutter實現這個用自帶的BottomNavigationBar估計不行,可能需要自定義一個底部導航。
看完上述內容,是不是對如何實現flutter仿微信底部圖標漸變功能有進一步的了解,如果還想學習更多內容,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。