Ad

How To Implement A Manual Carousel Slider In Flutter?

- 1 answer

I am creating a product image carousel which contains pictures of shoes where the user can change the image to be viewed by selecting a different color.
The user can manually scroll through the images without an issue,however when I try to manually change the displayed carousel image, only the indicator changes, but the image remains on the first image.

class DetailsPage extends StatefulWidget {
  final String url;
  final String title;
  final int index;
  DetailsPage({this.url, this.title, this.index});

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

class _DetailsPageState extends State<DetailsPage> {
  List imgList = [
    'https://i.dlpng.com/static/png/6838599_preview.png',
    'https://www.manelsanchez.pt/uploads/media/images/nike-air-force-max-ii-blue-fury-18.jpg',
    'https://www.vippng.com/png/detail/30-302339_nike-women-running-shoes-png-image-transparent-background.png',
  ];
  int _current = 0;
  String selected = "grey";

  List<T> map<T>(List list, Function handler) {
    List<T> result = [];
    for (var i = 0; i < list.length; i++) {
      result.add(handler(i, list[i]));
    }
    return result;
  }

  final CarouselController _buttonCarouselController = CarouselController();


  @override
  Widget build(BuildContext context) {   
    return Scaffold(
        backgroundColor: Theme.of(context).canvasColor,
        appBar: AppBar(
            title: Center(
              child: Text(
                'Details',
                style: TextStyle(
                    fontFamily: 'OpenSansLight',
                    fontSize: 26,
                    color: Theme.of(context).textTheme.headline1.color),
              ),
            ),
         
        body: ListView(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                     //Carousel Slider
                      CarouselSlider.builder(
                          options: CarouselOptions(
                              carouselController: _buttonCarouselController,
                              height: 200.0,
                              enlargeCenterPage: true,
                              enlargeStrategy: CenterPageEnlargeStrategy.height,
                              initialPage: 0,
                              reverse: false,
                              autoPlay: false,
                              enableInfiniteScroll: false,
                              scrollDirection: Axis.horizontal,
                              onPageChanged: (index, fn) {
                                setState(() {
                                  _current = index;
                                });
                              }),
                          itemCount: imgList.length,
                          itemBuilder: (BuildContext context, int index) =>
                              Builder(builder: (BuildContext context) {
                            return Image.network(
                              imgList[index],
                              fit: BoxFit.contain,
                            );
                          }),
                        
                      ),
                      SizedBox(height: 10),
                     //Indicator to show current index of images
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: map<Widget>(imgList, (index, url) {
                          return Container(
                            width: 30.0,
                            height: 2.0,
                            margin: EdgeInsets.symmetric(
                                vertical: 10.0, horizontal: 4.0),
                            decoration: BoxDecoration(
                              shape: BoxShape.rectangle,
                              borderRadius: BorderRadius.circular(10.0),
                              color: _current == index
                                  ? Colors.deepPurple
                                  : Colors.grey,
                            ),
                          );
                        }),
                      ),
                    Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Container(
                          height: 30,
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Text('Color',
                                  style: TextStyle(
                                      fontFamily: 'OpenSansLight',
                                      fontSize: 24)),
                            ],
                          ),
                        ),
                      ),
                      Flexible(
                        fit: FlexFit.loose,
                        child: Container(
                          width: width,
                          height: 120,
                          child: ListView.builder(
                            scrollDirection: Axis.horizontal,
                            itemCount: imgList.length,
                            itemBuilder: (BuildContext context, int index) {
                             //Color selector from images to manually control the carousel 
                             return GestureDetector(
                                onTap: () {
                                  setState(() {
                                    selected = imgList[index];
                                    _current = index;
                                    _buttonCarouselController
                                        .animateToPage(_current);
                                    print('I HAVE SELECTED $selected');
                                  });
                                },
                                child: ColorTicker(
                                  image: imgList[index],
                                  selected: selected == imgList[index],
                                ),
                              );
                            },
                          ),
                        ),
                      ), 
                     ],
                    ),
                   );

Color Ticker Widget

class ColorTicker extends StatelessWidget {
  final image;

  final bool selected;
 
  ColorTicker({this.image, this.selected});

  @override
  Widget build(BuildContext context) {
    print(selected);
    return Container( 
      margin: EdgeInsets.all(5),
      width: 100,
      height: 100,
      decoration: BoxDecoration(
          image: DecorationImage(
              fit: BoxFit.scaleDown, image: NetworkImage(image)),
          shape: BoxShape.circle,
          border: selected
              ? Border.all(color: Colors.deepPurple, width: 3)
              : Border.all(color: Colors.grey[500])),
      // color: color.withOpacity(0.7)),

      child: selected
          ? Center(child: Icon(Icons.check, size: 40, color: Colors.deepPurple))
          : Container(),
    );
  }
}

I've tried all I could from the documentation : https://pub.dev/packages/carousel_slider/example
But I kept getting an error

Unhandled Exception: NoSuchMethodError: The getter 'options' was called on null
Ad

Answer

I am almost embarassed at my mistake.
In the configuration of the slider, I placed the controller in the wrong place.
I put the controller inside the Carousel options instead of under CarouselSlider

CarouselSlider(
               carouselController: _buttonCarouselController,
               options: CarouselOptions(
                              ... ))

It now works :)

Ad
source: stackoverflow.com
Ad