PageView

PageView 控件可以实现一个“图片轮播”的效果,PageView 不仅可以水平滑动也可以垂直滑动。

  1. PageView({
  2. Key key,
  3. this.scrollDirection = Axis.horizontal,
  4. this.reverse = false,
  5. PageController controller,
  6. this.physics,
  7. this.pageSnapping = true, //是否自动切合(是否非自由模式)
  8. this.onPageChanged, //slider 切换时回调,回调参数为改变后的索引
  9. List<Widget> children = const <Widget>[],
  10. this.dragStartBehavior = DragStartBehavior.start,
  11. this.allowImplicitScrolling = false,
  12. this.restorationId,
  13. this.clipBehavior = Clip.hardEdge,
  14. })

简单示例

fdtdttyddasdyrt.gif

  1. Container(
  2. height: 200,
  3. child: PageView(
  4. onPageChanged: (int index) {
  5. print('index => $index');
  6. },
  7. // pageSnapping: false,
  8. children: List.generate(
  9. 4,
  10. (index) => Container(
  11. color: Colors.primaries[index % Colors.primaries.length],
  12. child: Text('PageView $index', textScaleFactor: 4),
  13. ),
  14. ),
  15. ),
  16. ),

PageController 控制器

image.png

  1. PageView(
  2. controller: PageController(
  3. initialPage: 1, //表示当前加载第几页,默认第一页。
  4. keepPage: true,
  5. viewportFraction: 0.9, //slider 左右缩小倍数
  6. ),
  7. ...
  8. )

PageView.builder

  1. PageView.builder({
  2. ...
  3. @required IndexedWidgetBuilder itemBuilder,
  4. int itemCount,
  5. ...
  6. })

无限滚动
  1. import "package:flutter/material.dart";
  2. import 'package:app1/coms/base/empty_null/empty_null.dart';
  3. class TestPage extends StatefulWidget {
  4. @override
  5. _TestPageState createState() => _TestPageState();
  6. }
  7. class _TestPageState extends State<TestPage> {
  8. List sliders = [PageViewSlider(1), PageViewSlider(2), PageViewSlider(3)];
  9. @override
  10. Widget build(BuildContext context) {
  11. return Scaffold(
  12. appBar: EmptyNull.appBar(),
  13. body: Container(
  14. height: 200,
  15. child: PageView.builder(
  16. itemCount: 10000,
  17. itemBuilder: (context, index) {
  18. return sliders[index % sliders.length];
  19. },
  20. ),
  21. ),
  22. );
  23. }
  24. }
  25. class PageViewSlider extends StatelessWidget {
  26. PageViewSlider(this.index);
  27. final int index;
  28. @override
  29. Widget build(BuildContext context) {
  30. return Container(
  31. color: Colors.primaries[index % Colors.primaries.length],
  32. child: Text('PageView $index', textScaleFactor: 4),
  33. );
  34. }
  35. }

库 flutter_swiper

https://pub.dev/packages/flutter_swiper
中文说明:https://github.com/best-flutter/flutter_swiper/blob/master/README-ZH.md

flutter最强大的siwiper, 多种布局方式,无限轮播,Android和IOS双端适配。

配置依赖
  1. dependencies:
  2. flutter_swiper: ^1.1.6

导入
  1. import 'package:flutter_swiper/flutter_swiper.dart';

基本示例

image.png

  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_swiper/flutter_swiper.dart';
  3. class FlutterSwiper extends StatefulWidget {
  4. @override
  5. _FlutterSwiperState createState() => _FlutterSwiperState();
  6. }
  7. class _FlutterSwiperState extends State<FlutterSwiper> {
  8. static List<String> list = [
  9. 'https://lstatic.zuimeia.com/common/image/2020/12/1/f6f251bb-132d-46e7-8740-0b0425bddae3_4835_1450.jpeg',
  10. 'https://lstatic.zuimeia.com/common/image/2020/11/3/cb418da0-d7a3-4b8c-829f-8cdf23ff1b08_4834_1450.jpeg',
  11. 'https://lstatic.zuimeia.com/common/image/2020/12/1/b4d482f1-d7cf-4af0-a70a-b35c7cb60fff_4835_1450.jpeg',
  12. 'https://lstatic.zuimeia.com/common/image/2020/5/28/7a62d3f3-f1f0-4963-98be-27f44c9628cc_2320_696.jpeg',
  13. ];
  14. @override
  15. Widget build(BuildContext context) {
  16. return Container(
  17. child: Column(
  18. children: [
  19. Container(
  20. width: double.infinity,
  21. color: Colors.grey,
  22. child: AspectRatio(
  23. aspectRatio: 16 / 6,
  24. child: Swiper(
  25. itemCount: 4,
  26. itemBuilder: (context, index) {
  27. return Container(
  28. child: Image.network(list[index], fit: BoxFit.fill),
  29. );
  30. },
  31. pagination: SwiperPagination(),
  32. control: SwiperControl(),
  33. ),
  34. ),
  35. ),
  36. Row(
  37. children: [
  38. Text('我是一个文本'),
  39. ],
  40. ),
  41. ],
  42. ),
  43. );
  44. }
  45. }

参数

基本参数
  • itemWidth、itemHeight
  • containerWidth、containerHeight
  • scrollDirection 滚动方向(默认 Axis.horizontal)
  • itemCount 数量
  • itemBuilder 构造器 (Widget Function(BuildContext context, int index);)

  • autoplay 是否自动轮播(默认 false)
  • autoplayDisableOnInteraction 互动时是否禁止轮播(默认 true)
  • autoplayDelay 轮播间隔时间(默认 3000毫秒)
  • duration 轮播切换动画时间(默认 300毫秒)
  • loop 无限轮播模式开关(默认 true)
  • curve 动画运动方式(默认 curve: Curves.ease,)

  • viewportFraction slider 左右缩小倍数。如:viewportFraction: 0.8,
  • scale 上下缩小倍数(当前slider高度不缩放)。如:scale: 0.9,
  • fade

  • pagination 设置 pagination: SwiperPagination() 展示默认分页指示器
  • control 设置 control: SwiperControl() 展示默认分页按钮

  • index 初始下标位置(默认 0)
  • onIndexChanged 当用户手动拖拽或者自动播放引起下标改变的时候调用(void onIndexChanged(int index))
  • onTap 当用户点击某个轮播的时候调用(void onTap(int index))

  • layout
  • customLayoutOption
  • indicatorLayout

分页指示器

分页指示器继承自 SwiperPlugin,SwiperPluginSwiper 提供额外的界面.设置为new SwiperPagination() 展示默认分页.

参数 默认值 描述
alignment Alignment.bottomCenter 如果要将分页指示器放到其他位置,那么可以修改这个参数
margin const EdgeInsets.all(10.0) 分页指示器与容器边框的距离
builder SwiperPagination.dots 目前已经定义了两个默认的分页指示器样式: SwiperPagination.dotsSwiperPagination.fraction,都可以做进一步的自定义.

如果需要定制自己的分页指示器,那么可以这样写:

  1. new Swiper(
  2. ...,
  3. pagination: SwiperCustomPagination(
  4. builder:(BuildContext context, SwiperPluginConfig config){
  5. return new YourOwnPaginatipon();
  6. }
  7. )
  8. );
  9. pagination: SwiperPagination(
  10. margin: EdgeInsets.all(2),
  11. builder: DotSwiperPaginationBuilder(
  12. activeColor: Color.fromRGBO(255, 255, 255, 0.4),
  13. color: Color.fromRGBO(255, 255, 255, 1),
  14. size: 7,
  15. ),
  16. ),

控制按钮

控制按钮组件也是继承自 SwiperPlugin,设置 new SwiperControl() 展示默认控制按钮.

参数 默认值 描述
iconPrevious Icons.arrow_back_ios 上一页的IconData
iconNext Icons.arrow_forward_ios 下一页的IconData
color Theme.of(context).primaryColor 控制按钮颜色
size 30.0 控制按钮的大小
padding const EdgeInsets.all(5.0) 控制按钮与容器的距离

控制器(SwiperController)

SwiperController 用于控制 Swiper的index属性, 停止和开始自动播放. 通过 new SwiperController() 创建一个SwiperController实例,并保存,以便将来能使用。

方法 描述
void move(int index, {bool animation: true}) 移动到指定下标,设置是否播放动画
void next({bool animation: true}) 下一页
void previous({bool animation: true}) 上一页
void startAutoplay() 开始自动播放
void stopAutoplay() 停止自动播放

内建的布局

示例1

layout1.gif

  1. new Swiper(
  2. itemBuilder: (BuildContext context, int index) {
  3. return new Image.network(
  4. "http://via.placeholder.com/288x188",
  5. fit: BoxFit.fill,
  6. );
  7. },
  8. itemCount: 10,
  9. viewportFraction: 0.8,
  10. scale: 0.9,
  11. )

示例2

layout2.gif

  1. new Swiper(
  2. itemBuilder: (BuildContext context, int index) {
  3. return new Image.network(
  4. "http://via.placeholder.com/288x188",
  5. fit: BoxFit.fill,
  6. );
  7. },
  8. itemCount: 10,
  9. itemWidth: 300.0,
  10. layout: SwiperLayout.STACK,
  11. )

示例3

layout3.gif

  1. new Swiper(
  2. itemBuilder: (BuildContext context, int index) {
  3. return new Image.network(
  4. "http://via.placeholder.com/288x188",
  5. fit: BoxFit.fill,
  6. );
  7. },
  8. itemCount: 10,
  9. itemWidth: 300.0,
  10. itemHeight: 400.0,
  11. layout: SwiperLayout.TINDER,
  12. )

示例4:

layout4.gif

构建你自己的动画十分简单:

  1. new Swiper(
  2. layout: SwiperLayout.CUSTOM,
  3. customLayoutOption: new CustomLayoutOption(
  4. startIndex: -1,
  5. stateCount: 3
  6. ).addRotate([
  7. -45.0/180,
  8. 0.0,
  9. 45.0/180
  10. ]).addTranslate([
  11. new Offset(-370.0, -40.0),
  12. new Offset(0.0, 0.0),
  13. new Offset(370.0, -40.0)
  14. ]),
  15. itemWidth: 300.0,
  16. itemHeight: 200.0,
  17. itemBuilder: (context, index) {
  18. return new Container(
  19. color: Colors.grey,
  20. child: new Center(
  21. child: new Text("$index"),
  22. ),
  23. );
  24. },
  25. itemCount: 10)

CustomLayoutOption 被设计用来描述布局和动画,很简单的可以指定每一个元素的状态.

  1. new CustomLayoutOption(
  2. startIndex: -1, /// 开始下标
  3. stateCount: 3 /// 下面的数组长度
  4. ).addRotate([ // 每个元素的角度
  5. -45.0/180,
  6. 0.0,
  7. 45.0/180
  8. ]).addTranslate([ /// 每个元素的偏移
  9. new Offset(-370.0, -40.0),
  10. new Offset(0.0, 0.0),
  11. new Offset(370.0, -40.0)
  12. ])

代码

swiper-example.gif

  1. new ConstrainedBox(
  2. child: new Swiper(
  3. outer:false,
  4. itemBuilder: (c, i) {
  5. return new Wrap(
  6. runSpacing: 6.0,
  7. children: [0,1,2,3,4,5,6,7,8,9].map((i){
  8. return new SizedBox(
  9. width: MediaQuery.of(context).size.width/5,
  10. child: new Column(
  11. mainAxisSize: MainAxisSize.min,
  12. children: <Widget>[
  13. new SizedBox(
  14. child: new Container(
  15. child: new Image.network("https://fuss10.elemecdn.com/c/db/d20d49e5029281b9b73db1c5ec6f9jpeg.jpeg%3FimageMogr/format/webp/thumbnail/!90x90r/gravity/Center/crop/90x90"),
  16. ),
  17. height: MediaQuery.of(context).size.width * 0.12,
  18. width: MediaQuery.of(context).size.width * 0.12,
  19. ),
  20. new Padding(padding: new EdgeInsets.only(top:6.0),child: new Text("$i"),)
  21. ],
  22. ),
  23. );
  24. }).toList(),
  25. );
  26. },
  27. pagination: new SwiperPagination(
  28. margin: new EdgeInsets.all(5.0)
  29. ),
  30. itemCount: 10,
  31. ),
  32. constraints:new BoxConstraints.loose(new Size(screenWidth, 170.0))
  33. ),

这里可以找到所有的定制选项

https://github.com/jzoom/flutter_swiper/blob/master/example/lib/src/ExampleCustom.dart