Flutter開發(fā)Widgets?之?PageView使用示例
構(gòu)造方法以及參數(shù):
PageView可用于Widget的整屏滑動切換,如當(dāng)代常用的短視頻APP中的上下滑動切換的功能,也可用于橫向頁面的切換,如APP第一次安裝時的引導(dǎo)頁面,也可用于開發(fā)輪播圖功能.
PageView({
Key? key,
this.scrollDirection = Axis.horizontal, // 設(shè)置滾動方向 垂直 / 水平
this.reverse = false, // 反向滾動
PageController? controller, // 滾動控制類
this.physics, // 滾動邏輯 , 不滾動 / 滾動 / 滾動到邊緣是否反彈
this.pageSnapping = true, // 如果設(shè)置 false , 則無法進(jìn)行頁面手勢捕捉
this.onPageChanged, // 頁面切換時回調(diào)該函數(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(垂直)兩個,默認(rèn)是horizontal的
reverse這個就是規(guī)定了children(子節(jié)點)的排序是否是倒序,默認(rèn)false。這個參數(shù)在ListView也有,一般在做IM工具聊天內(nèi)容用ListView展示時需要倒序展示的。
controller可以傳入一個PageController的實例進(jìn)去,可以更好的控制PageView的各種動作,可以設(shè)置:
- 初始頁面(initialPage)、
- 是否保存PageView狀態(tài)(keepPage)
- 每一個PageView子節(jié)點的內(nèi)容占改視圖的比例(viewportFraction)
- 直接調(diào)轉(zhuǎn)到指定的PageView的子節(jié)點的方法(jumpToPage
- 動畫(平滑移動)到指定的PageView的子節(jié)點的方法(animateToPage)
- 到下一個PageView的子節(jié)點的方法(nextPage)
- 到上一個PageView的子節(jié)點的方法(previousPage)
從以上可以看出基本是普通輪播圖組件的API
physics就是設(shè)置滑動效果:
- NeverScrollablePhysics表示設(shè)置的不可滾動
- BouncingScrollPhysics表示滾動到底了會有彈回的效果,就是iOS的默認(rèn)交互
- ClampingScrollPhysics表示滾動到底了就給一個效果,就是Android的默認(rèn)交互
- FixedExtentScrollPhysics就是ios經(jīng)典選擇時間組件UIDatePicker那種交互。
pageSnapping就是設(shè)置是不是整頁滾動,默認(rèn)是true.
dragStartBehavior這個屬性是設(shè)置認(rèn)定開始拖動行為的方式,可以選擇的是down和start兩個,默認(rèn)是start. down是第一個手指按下認(rèn)定拖動開始,start是手指拖動才算開始。
allowImplicitScrolling這個屬性一般提供給視障人士使用的,默認(rèn)是fasle
基本用法
PageView控件可以實現(xiàn)一個“圖片輪播”的效果,PageView不僅可以水平滑動也可以垂直滑動,簡單用法如下:
PageView(
children: [
Container(color: Colors.red,),
Container(color: Colors.black,),
Container(color: Colors.yellow,),
],
);

PageView滾動方向默認(rèn)是水平,可以設(shè)置其為垂直方向:
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表示當(dāng)前加載第幾頁,默認(rèn)第一頁。
onPageChanged屬性是頁面發(fā)生變化時的回調(diào),用法如下:

無限滾動
PageView滾動到最后時希望滾動到第一個頁面,這樣看起來PageView是無限滾動的:
List<Widget> pageList = [PageView1(), PageView2(), PageView3()];
PageView.builder(
itemCount: 10000,
itemBuilder: (context, index) {
return pageList[index % (pageList.length)];
},
)

實現(xiàn)指示器
指示器顯示總數(shù)和當(dāng)前位置,通過onPageChanged確定當(dāng)前頁數(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),),
);
}

切換動畫
如此常見的切換效果顯然不能體驗我們獨特的個性,我們需要更炫酷的方式,看下面的效果:

在滑出的時候當(dāng)前頁面逐漸縮小并居中,通過給PageController添加監(jiān)聽獲取當(dāng)前滑動的進(jì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()) {
//當(dāng)前的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…
總結(jié):
相比熟悉Android和IOS開發(fā)的同學(xué)都會比較熟悉ViewPager,可以在界面上滑動多個界面View的切換。在Flutter中同樣有這樣的組建那就是PageView,相比于ViewPager它有著更加強(qiáng)大的功能,畢竟Flutter中Widget是一等公民,在實際開發(fā)中也是比較實用的組件,可以提升開發(fā)效率。
以上就是Flutter開發(fā)Widgets 之 PageView使用示例的詳細(xì)內(nèi)容,更多關(guān)于Flutter開發(fā)Widgets PageView的資料請關(guān)注腳本之家其它相關(guān)文章!
- Flutter?Widget?之package?mason實現(xiàn)詳解
- Flutter?Widget?之FocusableActionDetector使用詳解
- Flutter?Widget?之StatefulBuilder構(gòu)建方法詳解
- flutter InheritedWidget使用方法總結(jié)
- Flutter Widgets MediaQuery控件屏幕信息適配
- Flutter Widgets粘合劑CustomScrollView NestedScrollView滾動控件
- Flutter?Widgets之標(biāo)簽類控件Chip詳解
- Flutter?Widget之FutureBuilder使用示例詳解
相關(guān)文章
iOS開發(fā)之用javascript調(diào)用oc方法而非url
本文說的是非攔截URL進(jìn)行判斷,然后調(diào)用oc方法這種調(diào)用手段,所以不用討論說為什么不用url這種方法,具體看需求,有需要的可以參考。2016-07-07
Objective-C優(yōu)雅使用KVO觀察屬性值變化
這篇文章主要為大家介紹了Objective-C優(yōu)雅使用KVO觀察屬性值變化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
iOS mobileconfig配置文件進(jìn)行簽名的配置方法
這篇文章主要介紹了iOS mobileconfig配置文件進(jìn)行簽名的配置方法,給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02
iOS中.a和.framework靜態(tài)庫的創(chuàng)建與.bundle資源包的使用詳解
這篇文章主要給大家介紹了關(guān)于在iOS中.a和.framework靜態(tài)庫的創(chuàng)建與.bundle資源包的使用的相關(guān)資料,文中介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12

