import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; class CarouselSliderWidget extends StatefulWidget { final List items; final Widget Function(BuildContext context, T item, int index) onPageBuilder; final bool withNavs; final bool withInds; final double? height; final double viewportFraction; final double aspectRatio; final bool enlargeCenterPage; final bool autoPlay; final bool enableInfiniteScroll; final Function()? onLastClick; final Function(int index, CarouselPageChangedReason reason)? onPageChanged; final CarouselSliderController? controller; const CarouselSliderWidget({ super.key, required this.items, required this.onPageBuilder, this.withNavs = false, this.onLastClick, this.autoPlay = true, this.enableInfiniteScroll = true, this.enlargeCenterPage = true, this.height = 200, this.viewportFraction = 0.9, this.aspectRatio = 16 / 9, this.withInds = true, this.controller, this.onPageChanged, }); @override State> createState() => _CarouselSliderWidgetState(); } class _CarouselSliderWidgetState extends State> { int activeIndex = 0; late final CarouselSliderController _controller = widget.controller ?? CarouselSliderController(); @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ CarouselSlider.builder( carouselController: _controller, itemCount: widget.items.length, itemBuilder: (context, index, realIndex) { return widget.onPageBuilder(context, widget.items[index], index); }, options: CarouselOptions( height: widget.height, autoPlay: widget.autoPlay, enableInfiniteScroll: widget.enableInfiniteScroll, enlargeCenterPage: widget.enlargeCenterPage, aspectRatio: widget.aspectRatio, viewportFraction: widget.viewportFraction, onPageChanged: (index, reason) { widget.onPageChanged?.call(index, reason); setState(() => activeIndex = index); }, ), ), if (widget.withInds || widget.withNavs) Padding( padding: const EdgeInsets.all(16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (widget.withInds) Expanded(child: Center(child: buildIndicator())), if (widget.withNavs) Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Opacity( opacity: activeIndex != 0 ? 1 : 0, child: IconButton( icon: const Icon(Icons.arrow_back_ios_new_rounded), onPressed: () => _controller.previousPage(), ), ), Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( shape: BoxShape.circle, color: Theme.of(context).primaryColor), child: InkWell( highlightColor: Theme.of(context).primaryColor, onTap: () { if (activeIndex == widget.items.length - 1) { if (widget.onLastClick != null) { widget.onLastClick!(); } } else { _controller.nextPage(); } }, child: const Icon(Icons.arrow_forward_ios_rounded), ), ), ], ), ), ], ), ), ], ); } Widget buildImage(String urlImage, int index) => Container( margin: const EdgeInsets.symmetric(horizontal: 12), color: Colors.grey, child: Image.network( urlImage, fit: BoxFit.cover, ), ); Widget buildIndicator() => AnimatedSmoothIndicator( activeIndex: activeIndex, count: widget.items.length, effect: ExpandingDotsEffect( dotWidth: 10, dotHeight: 10, activeDotColor: Theme.of(context).primaryColor, dotColor: Theme.of(context).colorScheme.onSurface, ), ); }