Flutter (二十) 轮播图

轮播图

  • CarouselView系统自带的,基于CustomScrollView。
  • CarouselSlider 第三方插件,基于PageView。

CarouselView

  • reverse 默认第一页往左,右边出来第二页。这里设置true。则手势方向往右,第二页从左边出来。
  • shape: RoundedRectangleBorder(borderRadius: BorderRadius.zero),默认会有圆角,这里取消圆角。
  • padding: EdgeInsets.zero,默认会有边距,这里取消边距。
  • itemSnapping保证按页显示,第一页完整显示。如果有多个页面,只保证第一个完整显示。
arduino 复制代码
          // CarouselView 是 Material 3 的轮播组件(Flutter 3.27+)。
          // 必填参数:
          //   - itemExtent: 每个 item 在主轴方向的固定尺寸
          //   - children:    要展示的子项
          // 常用可选参数:
          //   - padding:        每个 item 外侧的内边距,默认 EdgeInsets.all(4)
          //   - backgroundColor: 每个 item 的背景色(默认取 surface)
          //   - elevation:      每个 item 的阴影高度,默认 0
          //   - shape:          每个 item 的形状,默认圆角 28 的 RoundedRectangleBorder
          //   - itemSnapping:   是否启用"吸附到 item"效果,默认 false
          //   - shrinkExtent:   滚动时首/尾 item 的最小尺寸,默认 0
          //   - onTap:          点击某个 item 时回调,参数为索引
          //   - onIndexChanged: "首位可见 item"变化时回调
          //   - enableSplash:   是否有 InkWell 水波纹,默认 true
less 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('CarouselView Test')),
        body: CarouselViewTest(),
      ),
    ),
  );
}

class CarouselViewTest extends StatefulWidget {
  CarouselViewTest({Key? key}) : super(key: key);

  @override
  _CarouselViewTestState createState() => _CarouselViewTestState();
}

class _CarouselViewTestState extends State<CarouselViewTest> {
  CarouselController carouselController = CarouselController();
  int _currentIndex = 0;

  @override
  void initState() {
    super.initState();
    // 方式二:通过 controller 监听(可以拿到实时 offset、判断动画过程等)
    carouselController.addListener(() {
      // 滚动过程中随时可以读取当前偏移和 leadingItem
      // print('实时 pixels: ${carouselController.position.pixels}');
      // print('实时 leadingItem: ${carouselController.leadingItem}');
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Container(
          color: Colors.green,
          child: CarouselView(
            // reverse: true,
            controller: carouselController,
            itemExtent: MediaQuery.of(context).size.width,
            padding: EdgeInsets.zero,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.zero),
            itemSnapping: true,
            // 方式一:onIndexChanged 回调,翻页完成后触发(推荐)
            onIndexChanged: (int index) {
              setState(() {
                _currentIndex = index;
              });
              debugPrint('切到了第 $index 页');
            },
            children: [
              Container(color: Colors.red),
              Container(color: Colors.blue),
              Container(color: Colors.yellow),
            ],
          ),
        ),
        // 底部指示器
        Positioned(
          bottom: 20,
          left: 0,
          right: 0,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: List.generate(3, (i) {
              return Container(
                margin: const EdgeInsets.symmetric(horizontal: 4),
                width: _currentIndex == i ? 20 : 8,
                height: 8,
                decoration: BoxDecoration(
                  color: _currentIndex == i ? Colors.white : Colors.white54,
                  borderRadius: BorderRadius.circular(4),
                ),
              );
            }),
          ),
        ),
      ],
    );
  }
}

对于页面控制

arduino 复制代码
          // controller 接收的是 CarouselController(不是 ScrollController)。
          // 常用 API:
          //   - animateToItem(index, {duration, curve}): 动画滚到指定项
          //   - jumpToItem(index): 瞬间跳到指定项
          //   - leadingItem: 当前"首位可见 item"的索引
          //   - initialItem: 初始化时让第 N 项作为首位可见
          // 同时配合 onIndexChanged 回调可以监听首位变化。

动态控制每一个Item的占比

scala 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('CarouselView Test')),
        body: CarouselViewTest(),
      ),
    ),
  );
}

class CarouselViewTest extends StatefulWidget {
  CarouselViewTest({Key? key}) : super(key: key);

  @override
  _CarouselViewTestState createState() => _CarouselViewTestState();
}

class _CarouselViewTestState extends State<CarouselViewTest> {
  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      child: CarouselView.weighted(
        // flexWeights: [1, 2, 1], // 显示3个
        flexWeights: [1, 2, 1, 2], // 显示4个
        onIndexChanged: (int index) {},
        children: [
          Container(color: Colors.red),
          Container(color: Colors.blue),
          Container(color: Colors.yellow),
          Container(color: Colors.black),
        ],
      ),
    );
  }
}

动态添加

数量太多,一次增加会内存消耗过多。

less 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('CarouselView Test')),
        body: CarouselViewTest(),
      ),
    ),
  );
}

class CarouselViewTest extends StatefulWidget {
  CarouselViewTest({Key? key}) : super(key: key);

  @override
  _CarouselViewTestState createState() => _CarouselViewTestState();
}

class _CarouselViewTestState extends State<CarouselViewTest> {
  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      child: CarouselView.builder(
        itemExtent: 200,
        itemCount: 1000,
        itemBuilder: (BuildContext context, int index) {
          // 黄金角分布,每个 index 颜色不同且稳定(不随 rebuild 闪烁)
          final hue = (index * 137.508) % 360;
          return Container(
            color: HSLColor.fromAHSL(1.0, hue, 0.7, 0.5).toColor(),
            alignment: Alignment.center,
            child: Text(
              '$index',
              textAlign: TextAlign.center,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
              style: const TextStyle(fontSize: 40, color: Colors.white),
            ),
          );
        },
      ),
    );
  }
}

无限轮播图

less 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('CarouselView Test')),
        body: CarouselViewTest(),
      ),
    ),
  );
}

class CarouselViewTest extends StatefulWidget {
  CarouselViewTest({Key? key}) : super(key: key);

  @override
  _CarouselViewTestState createState() => _CarouselViewTestState();
}

class _CarouselViewTestState extends State<CarouselViewTest> {
  CarouselController carouselController = CarouselController();
  int _currentIndex = 0;

  @override
  void initState() {
    super.initState();
    // 方式二:通过 controller 监听(可以拿到实时 offset、判断动画过程等)
    carouselController.addListener(() {
      // 滚动过程中随时可以读取当前偏移和 leadingItem
      // print('实时 pixels: ${carouselController.position.pixels}');
      // print('实时 leadingItem: ${carouselController.leadingItem}');
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Container(
          color: Colors.green,
          child: CarouselView(
            controller: carouselController,
            infinite: true,
            itemExtent: MediaQuery.of(context).size.width,
            padding: EdgeInsets.zero,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.zero),
            itemSnapping: true,
            // 方式一:onIndexChanged 回调,翻页完成后触发(推荐)
            onIndexChanged: (int index) {
              setState(() {
                _currentIndex = index;
              });
              debugPrint('切到了第 $index 页');
            },
            children: [
              Container(color: Colors.red),
              Container(color: Colors.blue),
              Container(color: Colors.yellow),
            ],
          ),
        ),
        // 底部指示器
        Positioned(
          bottom: 20,
          left: 0,
          right: 0,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: List.generate(3, (i) {
              return Container(
                margin: const EdgeInsets.symmetric(horizontal: 4),
                width: _currentIndex == i ? 20 : 8,
                height: 8,
                decoration: BoxDecoration(
                  color: _currentIndex == i ? Colors.white : Colors.white54,
                  borderRadius: BorderRadius.circular(4),
                ),
              );
            }),
          ),
        ),
      ],
    );
  }
}

CarouselSlider

    1. CarouselSlider() ------ 静态列表
    1. CarouselSlider.builder() ------ 按需构建(推荐,节省内存)
less 复制代码
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('CarouselView Test')),
        body: CarouselViewTest(),
      ),
    ),
  );
}

class CarouselViewTest extends StatefulWidget {
  CarouselViewTest({Key? key}) : super(key: key);

  @override
  _CarouselViewTestState createState() => _CarouselViewTestState();
}

class _CarouselViewTestState extends State<CarouselViewTest> {
  @override
  Widget build(BuildContext context) {
    return CarouselSlider(
      items: [
        // 这里设置宽度无效,是CarouselOptions的viewportFraction控制的
        Container(color: Colors.red, width: MediaQuery.of(context).size.width),
        Container(color: Colors.blue, width: MediaQuery.of(context).size.width),
        Container(
          color: Colors.yellow,
          width: MediaQuery.of(context).size.width,
        ),
      ],
      options: CarouselOptions(
        height:300,
        autoPlay: true,
        aspectRatio: 16 / 9,
        viewportFraction: 1,
      ),
    );
  }
}
相关推荐
前端snow1 小时前
ai agent - RAG 汇总
前端
计算机魔术师2 小时前
AI为拿高分不惜入侵网站:22个模型作弊审计,真相让人背脊发凉
前端
晓说前端2 小时前
TypeScript 核心语法应用 —— Vue 3 中的使用(下)
前端·javascript·typescript·类型系统
zhangminghuan2 小时前
微信小程序开发核心知识点全景解析(前端必备硬核基础)
前端·微信小程序·小程序
boooooooom2 小时前
尝尝咸淡:从朴素 RAG 到 Graph RAG——一个烹饪问答系统的三层检索升级之路
前端·后端·llm
cindershade2 小时前
让每条前端异常都能回答:该由谁修、为什么现在修
前端
bitbrowser3 小时前
Telegram提示尝试次数过多,换网络和重装有用吗
前端
研☆香3 小时前
前端简单的的变量声明
前端
赵大仁3 小时前
Next.js AI Route Handler 工程化:超时、流式与鉴权
前端·ai·鉴权·next.js·工程化