基本用法
PageView可以实现组件滑动效果。不仅可以水平滑动而且可以进行垂直滑动,简单使用如下:
PageView(
children: [
MyPage1(),
MyPage2(),
MyPage3(),
],
)
467322-20200229105341388-706954813.gif
PageView默认为水平(horizontal)滑动,如果变更为垂直滑动效果设置以下参数:
PageView(
scrollDirection: Axis.vertical,
...
)
PageView的页面控制器(controller)可以实现多种特效,通过以下参数控制页面占比:
PageView(
controller: PageController(
initialPage: 0,
viewportFraction: 0.9,
),
...
)
image.png
PageView页面控制器的initialPage是当前加载页面,默认第一页。
onPageChanged属性为页面变化后的回调函数,用法如下:
PageView(
onPageChanged: (int index){
},
...
)
无限循环
当PageView的页面滑动到最后时再重新返回第一个页面时,代码如下:
List pageList = [PageView1(), PageView2(), PageView3()];
PageView.builder(
itemCount: 10000,
itemBuilder: (context, index) {
return pageList[index % (pageList.length)];
},
)
加入indicator
indicator展示显示总数的当前位置,通过onPageChanged获取当前页数并更新indicator。
List pageList = ['PageView1', 'PageView2', 'PageView3'];
int _currentPageIndex = 0;
_buildPageView() {
return Center(
child: Container(
height: 230,
child: Stack(
children: [
PageView.builder(
onPageChanged: (int index) {
setState(() {
_currentPageIndex = index % (pageList.length);
});
},
itemCount: 10000,
itemBuilder: (context, index) {
return _buildPageViewItem(pageList[index % (pageList.length)]);
},
),
Positioned(
bottom: 10,
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: 28),
),
);
}
效果如下:
467322-20200229105349433-497229952.gif
切换动画
一般的切换效果不足以体现出个性化界面。制作一个更独特的效果如下:
图片上传不成功
当水平滑出时,当前页面缩小并边缘化。当前page控制器获取当前页并赋值
_pageController.addListener(() {
setState(() {
_currPageValue = _pageController.page;
});
});
完整代码如下:
class _ViewPageState extends State {
var imgList = [
'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2877516247,37083492&fm=26&gp=0.jpg',
'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2877516247,37083492&fm=26&gp=0.jpg'
];
PageController _pageController;
var _currPageValue = 0.0;
//Scaling factor
double _scaleFactor = .8;
//view page height
double _height = 230.0;
@override
void initState() {
super.initState();
_pageController = PageController(viewportFraction: 0.9);
_pageController.addListener(() {
setState(() {
_currPageValue = _pageController.page;
});
});
}
@override
void dispose() {
super.dispose();
_pageController.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
height: _height,
child: PageView.builder(
itemBuilder: (context, index) => _buildPageItem(index),
itemCount: 10,
controller: _pageController,
));
}
_buildPageItem(int index) {
double value;
if (_pageController.position.haveDimensions) {
value = _pageController.page - index;
} else {
// If haveDimensions is false, use _currentPage to calculate value.
value = (_currPageValue - index).toDouble();
}
// We want the peeking cards to be 160 in height and 0.38 helps
// achieve that.
value = (1 - (value.abs() * .38)).clamp(0, 1).toDouble();
return Transform(
// transform: matrix4,
transform: Matrix4.diagonal3Values(1.0, value, 1.0),
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),
),
),
),
);
}
}