Flutter開發(fā)Widgets?之?PageView使用示例
構造方法以及參數(shù):
PageView可用于Widget的整屏滑動切換,如當代常用的短視頻APP中的上下滑動切換的功能,也可用于橫向頁面的切換,如APP第一次安裝時的引導頁面,也可用于開發(fā)輪播圖功能.
PageView({ Key? key, this.scrollDirection = Axis.horizontal, // 設置滾動方向 垂直 / 水平 this.reverse = false, // 反向滾動 PageController? controller, // 滾動控制類 this.physics, // 滾動邏輯 , 不滾動 / 滾動 / 滾動到邊緣是否反彈 this.pageSnapping = true, // 如果設置 false , 則無法進行頁面手勢捕捉 this.onPageChanged, // 頁面切換時回調該函數(shù) List<Widget> children = const <Widget>[], this.dragStartBehavior = DragStartBehavior.start, this.allowImplicitScrolling = false, this.restorationId, this.clipBehavior = Clip.hardEdge, }) : assert(allowImplicitScrolling != null), assert(clipBehavior != null), controller = controller ?? _defaultPageController, childrenDelegate = SliverChildListDelegate(children), super(key: key);
具體參數(shù)說明:
scrollDirection主要是滾動的方向即horizontal(水平)和vertical(垂直)兩個,默認是horizontal的
reverse這個就是規(guī)定了children(子節(jié)點)的排序是否是倒序,默認false。這個參數(shù)在ListView也有,一般在做IM工具聊天內容用ListView展示時需要倒序展示的。
controller可以傳入一個PageController的實例進去,可以更好的控制PageView的各種動作,可以設置:
- 初始頁面(initialPage)、
- 是否保存PageView狀態(tài)(keepPage)
- 每一個PageView子節(jié)點的內容占改視圖的比例(viewportFraction)
- 直接調轉到指定的PageView的子節(jié)點的方法(jumpToPage
- 動畫(平滑移動)到指定的PageView的子節(jié)點的方法(animateToPage)
- 到下一個PageView的子節(jié)點的方法(nextPage)
- 到上一個PageView的子節(jié)點的方法(previousPage)
從以上可以看出基本是普通輪播圖組件的API
physics就是設置滑動效果:
- NeverScrollablePhysics表示設置的不可滾動
- BouncingScrollPhysics表示滾動到底了會有彈回的效果,就是iOS的默認交互
- ClampingScrollPhysics表示滾動到底了就給一個效果,就是Android的默認交互
- FixedExtentScrollPhysics就是ios經(jīng)典選擇時間組件UIDatePicker那種交互。
pageSnapping就是設置是不是整頁滾動,默認是true.
dragStartBehavior這個屬性是設置認定開始拖動行為的方式,可以選擇的是down和start兩個,默認是start. down是第一個手指按下認定拖動開始,start是手指拖動才算開始。
allowImplicitScrolling這個屬性一般提供給視障人士使用的,默認是fasle
基本用法
PageView控件可以實現(xiàn)一個“圖片輪播”的效果,PageView不僅可以水平滑動也可以垂直滑動,簡單用法如下:
PageView( children: [ Container(color: Colors.red,), Container(color: Colors.black,), Container(color: Colors.yellow,), ], );
PageView滾動方向默認是水平,可以設置其為垂直方向:
PageView( scrollDirection: Axis.vertical, ... )
PageView配合PageController可以實現(xiàn)非??犰诺男Ч?,控制每一個Page不占滿,
Container( height:200 , child: PageView( scrollDirection: Axis.horizontal, controller: PageController(viewportFraction: 0.9), children: [ Container(color: Colors.red,), Container(color: Colors.black,), Container(color: Colors.yellow,), ], ), );
PageController中屬性initialPage
表示當前加載第幾頁,默認第一頁。
onPageChanged
屬性是頁面發(fā)生變化時的回調,用法如下:
無限滾動
PageView滾動到最后時希望滾動到第一個頁面,這樣看起來PageView是無限滾動的:
List<Widget> pageList = [PageView1(), PageView2(), PageView3()]; PageView.builder( itemCount: 10000, itemBuilder: (context, index) { return pageList[index % (pageList.length)]; }, )
實現(xiàn)指示器
指示器顯示總數(shù)和當前位置,通過onPageChanged
確定當前頁數(shù)并更新指示器。
int _currentPageIndex = 0; List<Widget> pageList = [ Container(color: Colors.red,), Container(color: Colors.black,), Container(color: Colors.yellow,),]; _buildPageView(){ return Center( child: Container( height: 230, child: Stack( children: [ PageView.builder(itemBuilder: (context,index){ var val = pageList[index%(pageList.length)]; print(val); return _buildPageViewItem('${val}'); }), Positioned( bottom: 20, left: 0, right: 0, child: Container( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(pageList.length, (i){ return Container( margin: EdgeInsets.symmetric(horizontal: 5), width: 10, height: 10, decoration: BoxDecoration( shape: BoxShape.circle, color: _currentPageIndex==i?Colors.blue:Colors.grey ), ); }).toList(), ), ) ) ], ), ), ); } _buildPageViewItem(String txt,{Color color=Colors.red}){ return Container( color: color, alignment: Alignment.center, child: Text(txt,style: TextStyle(color: Colors.white,fontSize: 25),), ); }
切換動畫
如此常見的切換效果顯然不能體驗我們獨特的個性,我們需要更炫酷的方式,看下面的效果:
在滑出的時候當前頁面逐漸縮小并居中,通過給PageController添加監(jiān)聽獲取當前滑動的進度:
_pageController.addListener(() { setState(() { _currPageValue = _pageController.page; }); });
全部代碼:
/** * @Author wywinstonwy * @Date 2022/10/05 9:50 上午 * @Description: */ import 'package:demo202112/utils/common_appbar.dart'; import 'package:flutter/material.dart'; class WyPageView1 extends StatefulWidget { const WyPageView1({Key? key}) : super(key: key); @override _WyPageViewState createState() => _WyPageViewState(); } class _WyPageViewState extends State<WyPageView1> { int _currentPageIndex = 0; var imgList = [ 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2877516247,37083492&fm=26&gp=0.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1582796218195&di=04ce93c4ac826e19067e71f916cec5d8&imgtype=0&src=http%3A%2F%2Fhbimg.b0.upaiyun.com%2F344fda8b47808261c946c81645bff489c008326f15140-koiNr3_fw658' ]; late PageController _pageController; var _currPageValue=0; //縮放系數(shù) double _scaleFactor = .8; //view page height double _height = 230.0; @override void initState() { // TODO: implement initState super.initState(); _pageController=PageController(viewportFraction: 0.9); _pageController.addListener(() { setState(() { _currPageValue = _pageController.page; }); }); } @override void dispose() { // TODO: implement dispose super.dispose(); _pageController.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: getAppBar('PageView'), body: Container( height: _height, child: PageView.builder( itemBuilder: (context, index) => _buildPageItem(index), itemCount: 10, controller: _pageController, )), ); } _buildPageItem(int index) { Matrix4 matrix4 = Matrix4.identity(); if (index == _currPageValue.floor()) { //當前的item double currScale = (1 - (_currPageValue - index) * (1 - _scaleFactor)).toDouble(); var currTrans = _height * (1 - currScale) / 2; matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) ..setTranslationRaw(0.0, currTrans, 0.0); } else if (index == _currPageValue.floor() + 1) { //右邊的item var currScale = _scaleFactor + (_currPageValue - index + 1) * (1 - _scaleFactor); var currTrans = _height * (1 - currScale) / 2; matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) ..setTranslationRaw(0.0, currTrans, 0.0); } else if (index == _currPageValue.floor() - 1) { //左邊 var currScale = (1 - (_currPageValue - index) * (1 - _scaleFactor)).toDouble(); var currTrans = _height * (1 - currScale) / 2; matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) ..setTranslationRaw(0.0, currTrans, 0.0); } else { //其他,不在屏幕顯示的item matrix4 = Matrix4.diagonal3Values(1.0, _scaleFactor, 1.0) ..setTranslationRaw(0.0, _height * (1 - _scaleFactor) / 2, 0.0); } return Transform( transform: matrix4, child: Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), image: DecorationImage( image: NetworkImage(imgList[index % 2]), fit: BoxFit.fill), ), ), ), ); } }
gitdemo地址:gitee.com/wywinstonwy…
總結:
相比熟悉Android和IOS開發(fā)的同學都會比較熟悉ViewPager,可以在界面上滑動多個界面View的切換。在Flutter中同樣有這樣的組建那就是PageView,相比于ViewPager它有著更加強大的功能,畢竟Flutter中Widget是一等公民,在實際開發(fā)中也是比較實用的組件,可以提升開發(fā)效率。
以上就是Flutter開發(fā)Widgets 之 PageView使用示例的詳細內容,更多關于Flutter開發(fā)Widgets PageView的資料請關注腳本之家其它相關文章!
相關文章
Objective-C中類和方法的定義以及協(xié)議的使用
這篇文章主要介紹了Objective-C中類和方法的定義以及協(xié)議的使用,配合Mac下的Xcode IDE進行講解,需要的朋友可以參考下2016-01-01UITextView實現(xiàn)只允許鏈接交互不允許選擇圖片的方法
這篇文章主要介紹了UITextView實現(xiàn)只允許鏈接交互不允許選擇圖片的方法,文中介紹的非常詳細,相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-03-03詳解iOS應用使用Storyboard布局時的IBOutlet與IBAction
這篇文章主要介紹了iOS應用使用Storyboard布局時的IBOutlet與IBAction,文中還附帶講解了為什么IBOutlet屬性是weak的,需要的朋友可以參考下2016-04-04詳解iOS App中UiTabBarController組件的基本用法
UiTabBarController組件即是用來創(chuàng)建App中的Tab視圖切換選項欄,下面將詳解iOS App中UiTabBarController組件的基本用法,包括左右滑動切換標簽頁等基本功能的實現(xiàn),需要的朋友可以參考下2016-05-05實例講解iOS應用UI開發(fā)之基礎動畫的創(chuàng)建
這篇文章主要介紹了iOS應用UI開發(fā)之基礎動畫的創(chuàng)建,以關鍵幀動畫作為重要知識點進行講解,需要的朋友可以參考下2015-11-11