Flutter 实战:正真意义上的无限循环轮播器

本文介绍了一种基于Flutter实现的轮播器组件,通过简单的代码示例展示了如何创建无限循环的图片轮播效果,并提供了核心代码片段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果图

前言

最近感觉flutter的圈子异常的火爆,怀揣着一颗赤诚的学习之心,我也加入这个大家庭(大坑哈哈)

使用

废话不多说,先看下如何使用:

new MyPageComponent(datas, callback: RouterUtil.NavigatorPush(context, new CardView())),
复制代码

一行代码调用,datas是一个list数据源,callback是图片的点击事件。

大致的实现逻辑
List<PageComponentModel> imgs;
imgs = new List();
    imgs.add(widget.datas[widget.datas.length - 1]);
    imgs.addAll(widget.datas);
    imgs.add(widget.datas[0]);
复制代码

数据源是list里边放了个自定义的model暂时只放了图片的url和title。如上代码这边的实现是在数据源的头部把数据源的最后一个数据添加进去,在数据源的尾部把数据源的第一个数据添加进去,然后通过一些逻辑的处理实现了无限循环逻辑。

首先创建pageView
Widget _pageView(constraints, callback) =>
      new NotificationListener(
          onNotification: (ScrollNotification note) {
            if (note is ScrollEndNotification ||
                note is UserScrollNotification) { //判断动画是否结束,或者用户手动滚动
              _currentState = true;
            } else {
              _currentState = false;
            }
            setState(() {
              _currentPage = _pageController.page;
              _index = _currentPage.round();
              _isEndScroll = _currentState;
            });
          },
          child: new PageView.custom(
            physics: const PageScrollPhysics(
                parent: const BouncingScrollPhysics()),
            controller: _pageController,
            childrenDelegate: new SliverChildBuilderDelegate(
                  (context, index) =>
              new GestureDetector(child: new _ChildPage(
                imgs[index].imgPath,
                title: imgs[index].title,
                parallaxOffset: constraints.maxWidth / 2.0 *
                    (index - _currentPage),
              ),
                onTap: callback,),
              childCount: imgs.length,
            ),
            onPageChanged: (index) {
              if (index == imgs.length - 1) {
                new Future.delayed(
                    new Duration(milliseconds: 200)).then((lwh) {
                  _pageController.jumpToPage(1);
                });
              } else if (index == 0) {
                new Future.delayed(
                    new Duration(milliseconds: 200)).then((lwh) {
                  _pageController.jumpToPage(imgs.length - 2);
                });
              }
            },
          )
      );
复制代码

上边代码没什么好说的看一眼就明白,有一个地方需要注意的是 new Duration(milliseconds: 200)).then((lwh) { _pageController.jumpToPage(1);这句话这边添加了一个消息延迟处理跳转,由于_pageController.page获取到的是一个时时的位置double类型,然后在onPageChanged(index)是个int类型内部是通过四舍五入的,所以如果不加一个延迟的话动画会不那么平滑。

创建指示器
Widget _indicator() {
    List<Widget> radios = new List();
    for (int i = 1; i < imgs.length - 1; i++) {
      if (_index == 0) {
        _index = imgs.length - 2;
      } else if (_index == imgs.length - 1) {
        _index = 0;
      }
      IconData iconData = _index == i ? Icons.radio_button_checked : Icons
          .radio_button_unchecked;
      Icon icon = new Icon(iconData, color: Colors.grey[100], size: 8.0,);
      radios.add(icon);
    }
    return new Container(
      alignment: Alignment.bottomCenter,
      margin: const EdgeInsets.only(bottom: 10.0),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: radios,
      ),
    );
  }
}
复制代码

由于数据源的头尾都添加了一个数据,所以循环从下表1位置开始,创建个数为imgs的长度减去2,也就是datas的长度。

pageView子部件的简单实现
class _ChildPage extends StatelessWidget {
  _ChildPage(this.data, {
    Key key,
    this.parallaxOffset = 0.0,
    this.title,
  }) : super(key: key);

  final String title;
  final String data;
  final double parallaxOffset;

  @override
  Widget build(BuildContext context) =>
      new Center(
        child: new Center(
          child: new Stack(
            children: <Widget>[
              new FadeInImage.assetNetwork(
                imageScale: 0.0,
                placeholder: "assets/images/ic_error.png",
                image: data,
                fit: BoxFit.fill,),
              new Container(
                alignment: Alignment.bottomCenter,
                margin: const EdgeInsets.only(bottom: 20.0),
                child: new Transform(
                  transform: new Matrix4.translationValues(
                      parallaxOffset, 0.0, 0.0),
                  child: Text(
                    title, style: new TextStyle(color: Colors.grey[100]),),
                ),
              ),
            ],
          ),
        ),
      );
}
复制代码

就是一张图片加一个标题

组合部件
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new LayoutBuilder(
          builder: (context, constraints) =>
          new Stack(children: <Widget>[
            _pageView(constraints, widget.callback),
            _indicator(),
          ],
          )
      ),
    );
  }
复制代码
创建轮询
timer = new Timer.periodic(new Duration(seconds: 3), (timer) {
      if (_isEndScroll) {
        print('lwh$_index');
        if (_index == imgs.length - 1) {
          _index = 1;
          _pageController.jumpToPage(_index);
        } else if (_index == 0) {
          _index = imgs.length - 1;
          _pageController.jumpToPage(_index);
        }
        _pageController.animateToPage(_index + 1,
            duration: new Duration(milliseconds: 500), curve: Curves.linear);
      }
    });
复制代码
结语

经过上边的几步,轮播器大致就实现了,如果有更高级的需求可以接着扩展。欢迎大家留言交流,一起学习。

最后附上github地址(哈哈 给个star支持一下):源码地址

转载于:https://juejin.im/post/5b5815055188251af6622e53

源码KIPageView,UITableView 很强大,可是只能竖向滚动;UICollectionView 可以解决各种布局难题,但是稍显复杂,对于一些简单的需求,有点杀鸡用牛刀的感觉。 在 iOS6 以前,还没有 UICollectionView,为了实现横向滚动的 UITableView,只有自己动手写组件。为了达到和 UITableView 差不多的效果,就得先弄清其内部实现机制是怎么回事。 在渲染 View 的时候,是很耗系统资源的,如果创建大量的 View, 系统运行将变得异常缓慢,甚至导致内存耗尽。但是,在实际应用中,我们难免会遇到大量的数据需要显示,如果每显示一个数据,我们都创建一个 View,那应用程序的体验将相当糟糕。所以 Apple 为 iOS 开发者提供了 UITableView,Google 为 Android 开发者提供了 ListView。 简单来讲,UITableView 采用复用机制,其只会显示其可见区域内的 UITableViewCell。我们在滑动的过程中,当超出 UITableView 可见区域的 Cell,将会从 UITableView 中移除,并加入回收池中以作复用。当 UITableView 需要显示新的 Cell,会先从回收池中查找是否有相应的 Cell 可以重用(通过 dequeueReusableCellWithIdentifier:)。如果有,则直接将其重新显示;如果没有,则创建新的 Cell。这样一来,就可以避免因创建过多的 View,导致内存耗尽的尴尬情况。 了解了其内部的运行原理,我们也可以实现一个自己的 UITableView。 很常见的一个应用场景——显示图片:如果显示一张图片,我们用一个 UIImageView 足矣,如果要显示多张图片,并且可以左右滚动,最简单的办法是用一个 UIScrollView 包含多个 UIImageView, 但是这样带来的后果则是,如果图片数据量较大,那这个程序根本没有办法常使用。如果我们还需要实现无限循环滚动,那这个解决方案肯定是不行的。所以这时候,就得我们自己实现一个 UITableView。 最开始,我写了一个组件叫 KIFlowView,实现了上面讲的需求,但是都是 iOS5 时代的产物了,难免过于陈旧。在后续的工作中也发现,类似的需求其实挺多的,比如左右滑动的 View,如网易新闻客户端,可以左右滑动,在不同的新闻栏目之间进行切换;有时候我们也需要实现一些 Tab,如果 Tab 的项目比较多,也需要考虑复用的问题,所以决定重新写一个增强组件,作为其替代品,所以就产生了 KIPageView。 测试环境:Xcode 6.2,iOS 6.0 以上
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值