Flutter Banner封装

Flutter 实现下拉刷新和自动加载更多
Flutter Banner封装
Flutter使用官方CustomScrollView实现复杂页面下拉刷新和加载更多
Flutter之Router和Navigator实现页面跳转
Flutter的基本应用

似乎好久没有写文章了,趁着最近项目时间不紧,总结一下项目中使用的部分Flutter组件。

项目中使用第三方的Banner插件 carousel_slider: ^4.2.1,但是这些组件一般是不能在项目直接使用的,我们一般会重新封装成简单易用于项目的组件。

// 轮播图点击Item回调
typedef OnItemClick = void Function(int, BannerModel);

class BannerWidget extends StatefulWidget {
  /// 轮播图数据
  final List<BannerModel> bannerList;

  /// 轮播图高度
  final double bannerHeight;

  /// 轮播图宽度
  final double bannerWidth;

  /// 轮播图viewportFraction 1.0 默认
  final double viewportFraction;

/// 指示器对齐方式
final MainAxisAlignment indicatorAlignment;

/// 指示器形状
final BoxShape indicatorShape;

/// 指示器颜色
final Color indicatorColor;

/// 指示器大小
final Size? indicatorSize;

/// 指示器间距
final double indicatorSpacing;

/// 点击回调
final OnItemClick? onItemClick;

const BannerWidget(
  {super.key,
  required this.bannerList,
  required this.bannerHeight,
  required this.bannerWidth,
  this.indicatorAlignment = MainAxisAlignment.center,
  this.indicatorShape = BoxShape.circle,
  this.indicatorColor = Colors.white,
  this.indicatorSize,
  this.viewportFraction = 1.0,
  this.indicatorSpacing = 2,
  this.onItemClick});

@override
State<BannerWidget> createState() => _BannerWidgetState();
}

class _BannerWidgetState extends State<BannerWidget> {
  final CarouselController _carouselController = CarouselController();
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
return Stack(
  children: [
    buildCarouselSlider(),
    Positioned(
      left: 0,
      right: 0,
      bottom: 10.wpx,
      child: Row(
        mainAxisAlignment: widget.indicatorAlignment,
        children: _buildIndicator(),
      ),
    ),
  ],
);
  }

  CarouselSlider buildCarouselSlider() {
return CarouselSlider(
    items: _items(),
    carouselController: _carouselController,
    options: CarouselOptions(
      height: widget.bannerHeight,
      viewportFraction: widget.viewportFraction,
      autoPlay: true,
      onPageChanged: (index, reason) {
        setState(() {
          _currentIndex = index;
        });
      },
    ));
}

  _items() {
return widget.bannerList.asMap().entries.map((entry) {
  return GestureDetector(
    onTap: () => widget.onItemClick?.call(entry.key, entry.value),
    child: Image.network(entry.value.icon!,
        width: widget.bannerWidth, fit: BoxFit.cover),
  );
}).toList();
}

  ///构建指示器
  _buildIndicator() {
return widget.bannerList.asMap().entries.map((entry) {
  return GestureDetector(
    onTap: () => _carouselController.animateToPage(entry.key),
    child: Container(
      margin: EdgeInsets.all(widget.indicatorSpacing),
      width: widget.indicatorSize?.width ?? 6.wpx,
      height: widget.indicatorSize?.height ?? 6.wpx,
      decoration: BoxDecoration(
        color: widget.indicatorColor
            .withOpacity(_currentIndex == entry.key ? 1.0 : 0.4),
        shape: widget.indicatorShape,
      ),
    ),
  );
}).toList();
  }
}

因为第三方插件没有指示器,所以项目中需要自行封装,本人Android开发所以代码和Android风格差不多,使用:

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage>
    with AutomaticKeepAliveClientMixin {

  @override
  Widget build(BuildContext context) {
super.build(context);

return Scaffold(
    .......
  body: BannerWidget(
    bannerList: HttpUrls.getBanner(),
    bannerHeight: 180.wpx,
    bannerWidth: MediaQuery.of(context).size.width,
    indicatorSize: Size(6.wpx, 6.wpx),
    indicatorShape: BoxShape.circle,
    indicatorColor: Colors.white,
    indicatorSpacing: 3.wpx,
    onItemClick: (index, model) {
      launchUrl(
        Uri.parse(model.url ?? ""),
        mode: LaunchMode.externalApplication,
      );
    },
  ),
);
  }
  .........
}

使用非常简单,点击Item 直接打开自带浏览器。最后需要记住了,不要为了封装而封装,有些东西是慢慢用久了才封装起来的,并不是一开始就想着封装。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容