flutter PageView 无限轮播

简单封装PageView


///文章中的rpx为适配单位,不需要可以去掉

class ManageReviewsPage extends StatefulWidget {
//数据源 
  final List pageData;
  //重写child,
  final Widget ?child;
  //指示点颜色,
  final Color ? unselectedIndicatorColor;
  final Color ? selectedIndicatorColor;
  //回调,父widget可以拿到索引值,
  final ValueChanged<int> ? pageViewCallback;

  const ManageReviewsPage({
    super.key,
    required this.pageData,  this.child, this.unselectedIndicatorColor, this.selectedIndicatorColor, this.pageViewCallback,
  });

  @override
  State<ManageReviewsPage> createState() => _ManageReviewsPageState();
}

class _ManageReviewsPageState extends State<ManageReviewsPage> {
  PageController controller = PageController();
  late List pageData;
  int currPageValue = 0;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    pageData = widget.pageData;
    //0~1 展示效果不一样
    controller = PageController(viewportFraction: 1);
  }


  @override
  Widget build(BuildContext context) {

    List<Widget> pageList = [];
    for (var element in pageData) {
      Widget pageWidget = widget.child ?? Container(
        clipBehavior: Clip.antiAlias,
        decoration: BoxDecoration(borderRadius: BorderRadius.circular(24.rpx)),
        child: Image.network(
          element,
          width: 702.rpx,
          fit: BoxFit.fitWidth,
        ),
      );
      pageList.add(pageWidget);
    }

    return Scaffold(
      appBar: AppBar(
        title: Text("manage"),
        centerTitle: true,
      ),
      body: ListView(
        shrinkWrap: true,
        children: [
          Container(
            margin: EdgeInsets.all(24.rpx),
            width: 702.rpx,
            height: 300.rpx,
            clipBehavior: Clip.antiAlias,
            decoration:
                BoxDecoration(borderRadius: BorderRadius.circular(24.rpx)),
            child: PageView.builder(
              controller: controller,
 ///重点,这里写大一点,这里的数据就是你能滑动的次数总和
              itemCount: 1000,
              //滑动触发的函数
              onPageChanged: (int index) {
                currPageValue =  index % (pageList.length);
                try {
                  widget.pageViewCallback!(currPageValue);
                } catch (_) {
                }

                setState(() {});
              },
              itemBuilder: (context, index) {
                return pageList[index % (pageList.length)];
              },
            ),
          ),
          //指示点UI
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              SizedBox(
                width: 48.rpx * pageData.length,
                height: 24.rpx,
                child: ListView.builder(
                    scrollDirection: Axis.horizontal,
                    shrinkWrap: true,
                    itemCount: pageData.length,
                    itemBuilder: (BuildContext context, int index) {
                      return Container(
                        width: 24.rpx,
                        height: 24.rpx,
                        margin: EdgeInsets.symmetric(horizontal: 12.rpx),
                        decoration: BoxDecoration(
                            shape: BoxShape.circle,
                            color: currPageValue == index
                                ? widget.unselectedIndicatorColor ??const Color(0xff1A71FF)
                                : widget.selectedIndicatorColor ??const Color(0xffC8CCD7)),
                      );
                    }),
              ),
            ],
          )
        ],
      ),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

}


简单使用


ManageReviewsPage(pageData: [
      "https://ts1.cn.mm.bing.net/th/id/R-C.61e10abb31be7153915f6550ad077542?rik=oukmhTAyezTNDw&riu=http%3a%2f%2fi3.img.969g.com%2fdown%2fimgx2014%2f12%2f22%2f289_093449_8ced3.jpg&ehk=mci1AffXHcwklYpn7cpFWSvZz3evIeDYflmll9wiy44%3d&risl=&pid=ImgRaw&r=0" ,
      "https://ts1.cn.mm.bing.net/th/id/R-C.61e10abb31be7153915f6550ad077542?rik=oukmhTAyezTNDw&riu=http%3a%2f%2fi3.img.969g.com%2fdown%2fimgx2014%2f12%2f22%2f289_093449_8ced3.jpg&ehk=mci1AffXHcwklYpn7cpFWSvZz3evIeDYflmll9wiy44%3d&risl=&pid=ImgRaw&r=0" ,
     "https://img.zcool.cn/community/01b2945b0663dda801218cf4617993.jpg@3000w_1l_0o_100sh.jpg",
     "https://img.zcool.cn/community/01b2945b0663dda801218cf4617993.jpg@3000w_1l_0o_100sh.jpg",

        ],
   
      ),


源码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、付费专栏及课程。

余额充值