Flutter笔记:发布一个多功能轮播组件 awesome_carousel

Flutter笔记 电商中文货币显示插件 Money Display


作者李俊才 (jcLee95)blog.csdn.net/qq_28550263
邮箱 : 291148484@163.com
本文地址blog.csdn.net/qq_28550263...
项目仓库thispage.tech:9680/jclee1995/f...
English Document: github.com/jacklee1995...


【简介】awesome_carousel 模块是一个Flutter轮播图模块。可以实现包括自定义指示器、动画、滚动等等众多功能。能够指定相当多地细节(可以参考 API 部分了解)。欢迎对本模块贡献代码和后续改进提出功能需求。

本文给出 awesome_carousel 模块的两个简单的用法示例。

这两个示例的效果预览如下:

目 录* * *

1. 从一个现实场景说起

我最近观察淘宝的商品展示轮播,发现不是那么直接,市面上没有找到可以直接套用的轮播组件。其中第一个轮播单元是商品的介绍视频,对应的轮播指示器是视频的进度条,而后续的轮播单元仅仅是轮播图片。比如:

因此我打算自己发布一个通用型模块,用于实现包括自定义指示器、动画、滚动等多功能的轮播插件。

2. 模块安装

csharp 复制代码
flutter pub add awesome_carousel

这将向你的包的 pubspec.yaml 中添加一行(并运行一个隐式的 flutter pub get):

yaml 复制代码
dependencies:
  awesome_carousel: ^1.0.0

改命令始终安装最新版本,随着时间推移版本号可能变化。需要安装指定版本也可以直接编辑 pubspec.yaml 文件后显示地运行 flutter pub get 命令。

3. 入门案例

3.1 入门示例1

本模块(awesome_carousel)提供的 Carousel 组件十分容易实现多种需求场景下的轮播功能,开发者可以定制轮播相关效果和轮播进度指示器。下面是两个使用 Carousel 组件默认的轮播进度指示器的例子:

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

class WidgetCarouSelDemo extends StatelessWidget {
  const WidgetCarouSelDemo({super.key});

  @override
  Widget build(BuildContext context) {
    final double width = MediaQuery.of(context).size.width;
    final double height = MediaQuery.of(context).size.height;
    final List<Color> colors = [      Colors.amber,      Colors.blue,      Colors.red,      Colors.green,      const Color.fromARGB(255, 59, 255, 177),    ];

    List<Widget> units = [];

    for (var i = 0; i < colors.length; i++) {
      units.add(
        Container(
          width: width,
          height: height,
          decoration: BoxDecoration(
            color: colors[i],
          ),
          child: Center(
            child: Text(
              'Page $i',
              style: const TextStyle(
                fontSize: 46,
                fontWeight: FontWeight.w900,
              ),
            ),
          ),
        ),
      );
    }

    return Column(
      children: [
        Carousel(
          units,
          indicatorShape: BoxShape.circle,
          indicatorWidth: 16,
          currentIndicatorColor: Colors.purple,
        ),
        const Divider(),
        ClipRRect(
          borderRadius: BorderRadius.circular(40.0), // 圆角半径
          child: Carousel(
            units.reversed.toList(),
            scrollDirection: Axis.vertical,
            indicatorShape: BoxShape.rectangle,
            indicatorWidth: 10,
            indicatorHeight: 10,
            currentIndicatorColor: Colors.pink,
            onUnitTapped: (index) => print('轮播单元 $index 被点击了'),
            onIndicatorTapped: (index) => print('进度指示单元 $index 被点击了'),
          ),
        )
      ],
    );
  }
}

其效果如下:

3.2 入门示例2

为了实现更加复杂的功能,需要定义更多的参数,以及使用轮播控制器。下面是一个自定义轮播进度指示器样式,并使用网络图片作为轮播单元的例子。

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

class NetworkImageCarouselDemo extends StatelessWidget {
  final List<String> imageUrls;

  final CarouselController _controller;

  const NetworkImageCarouselDemo(
    this.imageUrls,
    this._controller, {
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Carousel(
          _buildImages(context),
          height: 400.0, // 设置轮播图高度
          controller: _controller,
          indicatorColor: const Color.fromARGB(255, 190, 255, 130),
          // currentIndicatorColor: Colors.transparent,
          indicatorBuilder: _indicatorBuilder,
          // 当用户点击图像时触发的回调函数
          onUnitTapped: (int index) {
            print('点击了第 $index 张图片');
          },
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                _controller.toFirstPage();
              },
              child: const Text('首页'),
            ),
            const Spacer(
              flex: 1,
            ),
            ElevatedButton(
              onPressed: () {
                _controller.toPreviousPage();
              },
              child: const Text('上一页'),
            ),
            const Spacer(
              flex: 1,
            ),
            ElevatedButton(
              onPressed: () {
                _controller.toNextPage();
              },
              child: const Text('下一页'),
            ),
            const Spacer(
              flex: 1,
            ),
            ElevatedButton(
              onPressed: () {
                _controller.toLastPage();
              },
              child: const Text('尾页'),
            ),
          ],
        )
      ],
    );
  }

  List<Widget> _buildImages(BuildContext context) {
    List<Widget> res = [];
    for (String url in imageUrls) {
      res.add(
        Image.network(
          url,
          fit: BoxFit.cover, // 使图片宽度占满
          width: MediaQuery.of(context).size.width, // 设置宽度为屏幕宽度
          errorBuilder: (context, error, stackTrace) {
            // 在加载失败时返回一个占位图,确保图片占用固定高度
            return Container(
              height: MediaQuery.of(context).size.height,
              color: Colors.grey,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text(
                    'Image loading error:',
                    style: TextStyle(
                      color: Colors.red,
                    ),
                  ),
                  Text(
                    "原因: $error\n追溯:$stackTrace",
                    style: const TextStyle(
                      color: Colors.white,
                    ),
                    maxLines: 9,
                    overflow: TextOverflow.ellipsis,
                  ),
                ],
              ),
            );
          },
        ),
      );
    }
    return res;
  }

  Map<String, Widget> _indicatorBuilder(int index) {
    return {
      'plain': Container(
        padding: const EdgeInsets.all(10),
        child: Column(
          children: [
            const Text(
              'plain',
              style: TextStyle(
                color: Colors.grey,
              ),
            ),
            Container(
              width: 30,
              height: 10,
              decoration: const BoxDecoration(color: Colors.white),
            ),
          ],
        ),
      ),
      'active': Container(
        padding: const EdgeInsets.all(10),
        child: Column(
          children: [
            const Icon(
              Icons.arrow_circle_down,
              color: Colors.amber,
            ),
            const Text(
              'active',
              style: TextStyle(
                color: Colors.red,
                fontSize: 20,
                fontWeight: FontWeight.w700,
              ),
            ),
            Container(
              width: 30,
              height: 10,
              decoration: BoxDecoration(
                color: switch (index) {
                  0 => Colors.blue,
                  1 => Colors.red,
                  2 => Colors.green,
                  3 => Colors.pink,
                  _ => Colors.purple,
                },
              ),
            ),
          ],
        ),
      )
    };
  }
}

其效果如下:

可以看到,由于可以完全自定义轮播指示器和轮播项,只要你拥有足够丰富的想象力,可以包装出一些复杂但精致的轮播。

4. API 文档

CarouselController 类

CarouselController 类是一个用于管理轮播图控制的类。它包含了多个方法,用于控制轮播图的跳转、动画效果和状态通知。

构造函数

ini 复制代码
CarouselController(
  int total, {
  int initialPage = 0,
  bool keepPage = true,
  double viewportFraction = 1.0,
  Curve curve = Curves.ease,
  Duration duration = const Duration(milliseconds: 300),
})

参数

  • total (int): 表示轮播的总页面数量。
  • initialPage (int): 表示初始页面索引,默认为0。
  • keepPage (bool): 表示是否保持页面,即在翻页后是否保存页面状态,默认为 true
  • viewportFraction (double): 表示可视视口占整个页面宽度的比例,默认为 1.0。
  • curve (Curve): 页面切换动画曲线,默认为 Curves.ease
  • duration (Duration): 页面切换动画播放时间,默认为 Duration(milliseconds: 300)

方法

goToPage(int page)

此方法用于通过自定义方法滚动轮播到指定的页面。

  • page (int): 要跳转到的页面的索引。

toFirstPage()

此方法用于通过自定义方法将轮播滚动到第一个页面。

toPreviousPage()

此方法用于通过自定义方法将轮播滚动到上一页。如果当前已经是第一页,则会跳转到最后一页。

toNextPage()

此方法用于通过自定义方法将轮播滚动到下一页。如果当前已经是最后一页,则会跳转到第一页。

toLastPage()

此方法用于通过自定义方法将轮播滚动到最后一页。

属性

currentPage

  • 类型: int
  • 描述: 获取或设置当前轮播的页面索引。通过获取 currentPage 属性,可以获得当前页面的索引,通过设置 currentPage 属性,可以跳转到指定的页面。

示例

ini 复制代码
final controller = CarouselController(3);

// 获取当前页面索引
int current = controller.currentPage;

// 将轮播滚动到第二页
controller.goToPage(1);

// 将轮播滚动到下一页
controller.toNextPage();

Carousel 类是一个通用的轮播组件,它允许您在Flutter应用程序中创建各种类型的轮播图。您可以配置轮播图的外观、轮播控制和回调函数。

构造函数

ini 复制代码
Carousel(
  List<Widget> units, {
  Key? key,
  double height = 400.0,
  double width = 0.0,
  FunctionWithAInt? onUnitTapped,
  FunctionWithAInt? onIndicatorTapped,
  bool useindicator = true,
  Color indicatorColor = Colors.white,
  Color currentIndicatorColor = Colors.blue,
  double indicatorWidth = 40.0,
  double indicatorHeight = 26.0,
  double indicatorMargin = 3.0,
  double indicatorToBottom = 10.0,
  BoxShape indicatorShape = BoxShape.rectangle,
  FunctionIndicatorBuilder? indicatorBuilder,
  bool pageSnapping = true,
  bool padEnds = true,
  Clip clipBehavior = Clip.hardEdge,
  bool reverse = false,
  Axis scrollDirection = Axis.horizontal,
  CarouselController? controller,
})

参数

  • units (List): 要轮播的组件列表。
  • key (Key?): 可选参数,用于在小部件树中标识小部件。
  • height (double): 轮播组件的高度,默认为 400.0。
  • width (double): 轮播组件的宽度,默认为 0.0(自动适应屏幕宽度)。
  • onUnitTapped (FunctionWithAInt?): 当轮播单元被点击时触发的回调函数,可选,接收一个整数参数,表示被点击的单元索引。
  • onIndicatorTapped (FunctionWithAInt?): 当指示器被点击时触发的回调函数,可选,接收一个整数参数,表示被点击的指示器索引。
  • useindicator (bool): 控制是否显示轮播图下方的指示器,默认为 true
  • indicatorColor (Color): 指示器的默认颜色,默认为白色。
  • currentIndicatorColor (Color): 当前选中指示器的颜色,默认为蓝色。
  • indicatorWidth (double): 每个指示器的宽度,默认为 40.0。
  • indicatorHeight (double): 每个指示器的高度,默认为 26.0。
  • indicatorMargin (double): 指示器之间的水平间距,默认为 3.0。
  • indicatorToBottom (double): 指示器距离底部的距离,默认为 10.0。
  • indicatorShape (BoxShape): 指示器的形状,可以是 BoxShape.rectangleBoxShape.circle,默认为 BoxShape.rectangle
  • indicatorBuilder (FunctionIndicatorBuilder?): 自定义指示器构建函数,可选,用于创建指示器的自定义外观。
  • pageSnapping (bool): 是否启用页面快速吸附,默认为 true
  • padEnds (bool): 是否在轮播首尾添加额外的页面,默认为 true
  • clipBehavior (Clip): 指示如何剪切轮播单元的内容,默认为 Clip.hardEdge
  • reverse (bool): 是否以反向顺序滚动轮播单元,默认为 false
  • scrollDirection (Axis): 轮播单元滚动方向,可以是 Axis.horizontalAxis.vertical,默认为 Axis.horizontal
  • controller (CarouselController?): 轮播控制器,可选,用于控制轮播的行为和状态。
  • disableIndicatorDefaultCallbacks (bool): 是否禁用默认指示器回调函数,默认为 false。当为 true 时,不执行默认的指示器点击事件。

示例

less 复制代码
Carousel(
  [
    Image.network('https://example.com/image1.jpg'),
    Image.network('https://example.com/image2.jpg'),
    Image.network('https://example.com/image3.jpg'),
  ],
  height: 300.0,
  onUnitTapped: (int index) {
    print('点击了第 $index 个轮播单元');
  },
  indicatorColor: Colors.red,
  currentIndicatorColor: Colors.green,
),
相关推荐
我要最优解2 小时前
关于在mac中配置Java系统环境变量
java·flutter·macos
江上清风山间明月1 天前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
Zsnoin能2 天前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人2 天前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen2 天前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang2 天前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang2 天前
Flutter项目中设置安卓启动页
android·flutter
JIngles1232 天前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter
B.-2 天前
在 Flutter 中实现文件读写
开发语言·学习·flutter·android studio·xcode
freflying11193 天前
使用jenkins构建Android+Flutter项目依赖自动升级带来兼容性问题及Jenkins构建速度慢问题解决
android·flutter·jenkins