Flutter实现可循环轮播图效果

编辑: admin 分类: 安卓教程 发布时间: 2022-03-14 来源:互联网
目录
  • 壹、控件分解图
  • 贰、代码实现
    • 贰点壹、构建根布局
    • 贰点贰、构建PageView
    • 贰点叁、构建下方的Indicator布局
    • 贰点肆、PageView和TabPageSelector联动 & 定时自动翻页
    • 贰点五、循环翻页实现
  • 叁、可运行的完整代码

    效果图

    效果图

    壹、控件分解图

    控件拆解图

    贰、代码实现

    贰点壹、构建根布局

    新建AdPictureWidget继承自StatefulWidget,新建_AdPictureWidgetState类继承自State<AdPictureWidget>,根布局为Stack,代码如下:

    class AdPictureWidget extends StatefulWidget {
     @override
     _AdPictureWidgetState createState() => _AdPictureWidgetState();
    }
    
    class _AdPictureWidgetState extends State<AdPictureWidget>{
     @override
     Widget build(BuildContext context) {
      return Stack(
       children: <Widget>[
        ...
       ],
      );
     }
    }
    
    

    贰点贰、构建PageView

    PageView类似于Android里的ViewPager,我们可以使用PageController控制PageView 的滑动行为,比如设置滑动动画、令其滑动到指定的页面等等。可以通过设置onPageChanged来监听页面的滑动,相当于Android里的PageListener。每一个Page里的布局可以通过children属性进行设置,例子中每一个Page里包含一张图片,图片是通过网络来加载的。代码如下:

    class _AdPictureWidgetState extends State<AdPictureWidget>{
     PageController _pageController = PageController();
     List _adPictures = [];
     @override
     void dispose() {
      _pageController.dispose();
      super.dispose();
     }
     @override
     Widget build(BuildContext context) {
      return Stack(
       children: <Widget>[
        PageView(
         children: _adPictures.map((json) {
          var adPicture = AdPicture.fromJson(json);//可以先忽略这个实体类
          return Image.network(
           adPicture.imageUrl,
           fit: BoxFit.fill,//使照片占满整个屏幕
          );
         }).toList(),
         onPageChanged: _onPageChanged,
         controller: _pageController,
        ),
       ],
      );
     }
     
     void _onPageChanged(int index) {
      ...
     }
    }

    贰点叁、构建下方的Indicator布局

    屏幕下方的一行指示小圆点可以直接使用flutter的TabPageSelector搞定,使用Align控制其显示在屏幕的下方。我们只需要使用TabPageSelector的三个属性即可,通过color属性设置其未被选中时的颜色,通过selectedColor设置选中时的颜色,那如何控制选中还是未被选中呢,答案是它的controller属性,我们直接new出一个TabController类,将其赋值给controller属性即可,代码如下:

    class _AdPictureWidgetState extends State<AdPictureWidget>
      with SingleTickerProviderStateMixin {
     TabController _tabController;
     ...
     @override
     void initState() {
      _tabController = TabController(length: 0, vsync: this);
      super.initState();
     }
     @override
     void dispose() {
      ...
      _tabController.dispose();
      super.dispose();
     }
     @override
     Widget build(BuildContext context) {
      return Stack(
       children: <Widget>[
        PageView(
         ...
        ),
        Align(
         alignment: Alignment(0.0, 0.5),
         child: TabPageSelector(
          color: Colors.white,
          selectedColor: Colors.black,
          controller: _tabController,
         ),
        ),
       ],
      );
     }

    贰点肆、PageView和TabPageSelector联动 & 定时自动翻页

    二者的联动很简单,在PageView的滑动回调里调用_tabController的animateTo方法即可实现二者的联动。如果需要定时翻页,则需要使用到一个Timer的类,详细代码如下:

    const timeout = const Duration(seconds: 2);
    class _AdPictureWidgetState extends State<AdPictureWidget>
      with SingleTickerProviderStateMixin {
     ...
     Timer _timer;
     int _index = 0;
     @override
     void initState() {
      ...
      _timer = Timer.periodic(timeout, _handleTimeout);//一创建定时器就启动了,每过timeout时间就会调用_handleTimeout这个回调。
      super.initState();
     }
     @override
     void dispose() {
      ...
      _timer.cancel();
      super.dispose();
     }
     _handleTimeout(Timer timer) {
       _index++;
       _pageController.animateToPage(
        _index % (_adPictures.length),//跳转到的位置
        duration: Duration(milliseconds: 16),//跳转的间隔时间
        curve: Curves.fastOutSlowIn,//跳转动画
       );
       _tabController.animateTo(_index % (_adPictures.length));
     }

    贰点五、循环翻页实现

    在这里插入图片描述

    在这里插入图片描述

    假设只有三页,实现循环播放的原理是在原来的数据基础上,在最开始插入一张原本的尾页,在最末尾插入一张原本的首页(看上面两张图也许更形象),当用户滑动到现在的尾页时,程序自动的将其滑动到现在的第二页,滑动的很快对用户来说是无感之的,同理,当用户滑动到现在的首页时,程序自动滑动到现在的倒数第二页。这种方法在Android里也是挺常用的。

    叁、可运行的完整代码

    •依赖的第三方库:

      dio: 1.0.6 
      json_annotation: ^2.0.0

    •代码及文件名:

    ///文件名:AdPictureWidget.dart
    class AdPictureWidget extends StatefulWidget {
     @override
     _AdPictureWidgetState createState() => _AdPictureWidgetState();
    }
    const timeout = const Duration(seconds: 2);
    class _AdPictureWidgetState extends State<AdPictureWidget>
      with SingleTickerProviderStateMixin {
     TabController _tabController;
     PageController _pageController = PageController();
     Timer _timer;
     List _adPictures = [];
     int _index = 0;
     @override
     void initState() {
      _tabController = TabController(length: 0, vsync: this);
      _timer = Timer.periodic(timeout, _handleTimeout);
      loadAdPictures();
      super.initState();
     }
     @override
     void dispose() {
      _tabController.dispose();
      _timer.cancel();
      _pageController.dispose();
      super.dispose();
     }
     @override
     Widget build(BuildContext context) {
      return Stack(
       children: <Widget>[
        PageView(
         children: _adPictures.map((json) {
          var adPicture = AdPicture.fromJson(json);
          return Image.network(adPicture.imageUrl, fit: BoxFit.fill);
         }).toList(),
         onPageChanged: _onPageChanged,
         controller: _pageController,
        ),
        Align(
         alignment: Alignment(0.0, 0.5),
         child: TabPageSelector(
          color: Colors.white,
          selectedColor: Colors.black,
          controller: _tabController,
         ),
        ),
       ],
      );
     }
     _handleTimeout(Timer timer) {
      if (_adPictures.length - 2 != 0) {
       _index++;
       _pageController.animateToPage(
        _index % (_adPictures.length - 2),
        duration: Duration(milliseconds: 16),
        curve: Curves.fastOutSlowIn,
       );
      }
     }
     void _onPageChanged(int index) {
      _index = index;
      if (index == 0) {
       _tabController.animateTo(_tabController.length - 1);
       _pageController.jumpToPage(_adPictures.length - 2);
      } else if (index == _adPictures.length - 1) {
       _tabController.animateTo(0);
       _pageController.jumpToPage(1);
      } else {
       _tabController.animateTo(index - 1);
      }
     }
     void loadAdPictures() async {
      Dio dio = Dio();
      Response<List> response = await dio
        .get("http://www.wanandroid.com/tools/mockapi/2511/getAdPictures");
      List res = response.data;
      if (res.length != 0) {
       res.insert(0, res[res.length - 1]);
       res.add(res[1]);
       setState(() {
        _adPictures = res;
        _pageController.jumpToPage(1);
        _tabController =
          TabController(length: _adPictures.length - 2, vsync: this);
       });
      }
     }
    }
    
    ///文件名:AdPicture.dart
    library adpicture;
    import 'package:json_annotation/json_annotation.dart';
    part 'AdPicture.g.dart';
    ///首页轮播图
    @JsonSerializable()
    class AdPicture {
     final String imageUrl; //图片链接
     AdPicture({
      this.imageUrl,
     });
     factory AdPicture.fromJson(Map<String, dynamic> json) =>
       _$AdPictureFromJson(json);
    }
    
    ///文件名:AdPicture.g.dart
    part of adpicture;
    AdPicture _$AdPictureFromJson(Map<String, dynamic> json) {
     return AdPicture(imageUrl: json['imageUrl'] as String);
    }
    
    Map<String, dynamic> _$AdPictureToJson(AdPicture instance) => <String, dynamic>{
       'imageUrl': instance.imageUrl,
      };

    总结

    以上所述是小编给大家介绍的Flutter实现可循环轮播图效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对海外IDC网网站的支持!
    如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

    更多阅读