serenader2014 / flutter_carousel_slider

A flutter carousel widget, support infinite scroll, and custom child widget.
https://pub.dev/packages/carousel_slider
MIT License
1.55k stars 516 forks source link

InfiniteScroll and InitialPage do not work with key: #409

Open DexEze opened 11 months ago

DexEze commented 11 months ago

If the CarouselSlider is contained within a scrollview that has a 'key:' set, then the initialpage of the slider seems to be the 3rd page, and from that page you cannot slide backward. See the code below, it is using demo code from https://serenader2014.github.io/flutter_carousel_slider/#/complicated

import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';

final List<String> imgList = [
  'https://images.unsplash.com/photo-1520342868574-5fa3804e551c?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=6ff92caffcdd63681a35134a6770ed3b&auto=format&fit=crop&w=1951&q=80',
  'https://images.unsplash.com/photo-1522205408450-add114ad53fe?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=368f45b0888aeb0b7b08e3a1084d3ede&auto=format&fit=crop&w=1950&q=80',
  'https://images.unsplash.com/photo-1519125323398-675f0ddb6308?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=94a1e718d89ca60a6337a6008341ca50&auto=format&fit=crop&w=1950&q=80',
  'https://images.unsplash.com/photo-1523205771623-e0faa4d2813d?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=89719a0d55dd05e2deae4120227e6efc&auto=format&fit=crop&w=1953&q=80',
  'https://images.unsplash.com/photo-1508704019882-f9cf40e475b4?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=8c6e5e3aba713b17aa1fe71ab4f0ae5b&auto=format&fit=crop&w=1352&q=80',
  'https://images.unsplash.com/photo-1519985176271-adb1088fa94c?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=a0c8d632e977f94e5d312d9893258f59&auto=format&fit=crop&w=1355&q=80'
];

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

  @override
  State<TestPage> createState() => _TestPageState();
}

SliverAppBar showSliverAppBar(
    BuildContext context, String screenTitle, bool forceElevated) {
  final screenSize = MediaQuery.of(context).size;

  return SliverAppBar(
    forceElevated: forceElevated,
    elevation: 15,
    backgroundColor: Theme.of(context).colorScheme.primary,
    floating: true,
    pinned: true,
    snap: false,
    title: Row(
      children: [
        Text(
          screenTitle,
          textAlign: TextAlign.center,
        ),
      ],
    ),
    actions: [
      Padding(
        padding: EdgeInsets.only(
          right: screenSize.width * 0.01,
        ),
        child: IconButton(
          onPressed: () {},
          icon: const Icon(
            Icons.person,
          ),
        ),
      ),
    ],
    bottom: const TabBar(
      tabs: [
        Tab(
          icon: Icon(Icons.home),
          text: 'Home',
        ),
        Tab(
          icon: Icon(Icons.calendar_month_outlined),
          text: 'Calendar',
        ),
        Tab(
          icon: Icon(Icons.question_mark),
          text: 'About Us',
        ),
      ],
    ),
  );
}

class _TestPageState extends State<TestPage> {
  @override
  Widget build(BuildContext context) {
    final double height = MediaQuery.of(context).size.height * 0.7;
    final double width = MediaQuery.of(context).size.width;

    final List<String> tabs = <String>['Home', 'Calendar', 'About Us'];

    return DefaultTabController(
      length: tabs.length,
      child: Scaffold(
        body: NestedScrollView(
          floatHeaderSlivers: true,
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return [
              SliverOverlapAbsorber(
                handle:
                    NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                sliver: showSliverAppBar(context, 'Title', innerBoxIsScrolled),
              ),
            ];
          },
          body: TabBarView(
            children: [
              SafeArea(
                top: false,
                bottom: false,
                child: Builder(builder: (BuildContext context) {
                  return CustomScrollView(
                    scrollBehavior: ScrollConfiguration.of(context)
                        .copyWith(scrollbars: false),
                    key: PageStorageKey<String>(tabs[0]),
                    slivers: [
                      SliverOverlapInjector(
                        // This is the flip side of the SliverOverlapAbsorber
                        // above.
                        handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                            context),
                      ),
                      SliverList(
                        delegate: SliverChildListDelegate(
                          [
                            SizedBox(
                              height: height,
                              child: Stack(
                                children: [
                                  ComplicatedImageDemo(),
                                ],
                              ),
                            ),
                            Container(
                              height: 1500,
                              color: Colors.green,
                            ),
                          ],
                        ),
                      ),
                    ],
                  );
                }),
              ),
              SafeArea(
                top: false,
                bottom: false,
                child: Builder(builder: (BuildContext context) {
                  return CustomScrollView(
                    scrollBehavior: ScrollConfiguration.of(context)
                        .copyWith(scrollbars: false),
                    key: PageStorageKey<String>(tabs[1]),
                    slivers: [
                      SliverOverlapInjector(
                        // This is the flip side of the SliverOverlapAbsorber
                        // above.
                        handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                            context),
                      ),
                      SliverList(
                        delegate: SliverChildListDelegate(
                          [
                            Container(
                              height: 600,
                              color: Colors.blue[200],
                              child: Center(
                                child: Text(tabs[1],
                                    style: const TextStyle(fontSize: 40)),
                              ),
                            ),
                            Container(
                              height: 1200,
                              color: Colors.pink,
                            ),
                          ],
                        ),
                      ),
                    ],
                  );
                }),
              ),
              SafeArea(
                top: false,
                bottom: false,
                child: Builder(builder: (BuildContext context) {
                  return CustomScrollView(
                    scrollBehavior: ScrollConfiguration.of(context)
                        .copyWith(scrollbars: false),
                    key: PageStorageKey<String>(tabs[2]),
                    slivers: [
                      SliverOverlapInjector(
                        // This is the flip side of the SliverOverlapAbsorber
                        // above.
                        handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                            context),
                      ),
                      // Show other sliver stuff
                      SliverList(
                        delegate: SliverChildListDelegate(
                          [
                            Container(
                              height: 600,
                              color: Colors.blue[200],
                              child: Center(
                                child: Text(tabs[2],
                                    style: const TextStyle(fontSize: 40)),
                              ),
                            ),
                            Container(
                              height: 1200,
                              color: Colors.pink,
                            ),
                          ],
                        ),
                      ),
                    ],
                  );
                }),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

final List<Widget> imageSliders = imgList
    .map((item) => Container(
          child: Container(
            margin: EdgeInsets.all(5.0),
            child: ClipRRect(
                borderRadius: BorderRadius.all(Radius.circular(5.0)),
                child: Stack(
                  children: <Widget>[
                    Image.network(item, fit: BoxFit.cover, width: 1000.0),
                    Positioned(
                      bottom: 0.0,
                      left: 0.0,
                      right: 0.0,
                      child: Container(
                        decoration: BoxDecoration(
                          gradient: LinearGradient(
                            colors: [
                              Color.fromARGB(200, 0, 0, 0),
                              Color.fromARGB(0, 0, 0, 0)
                            ],
                            begin: Alignment.bottomCenter,
                            end: Alignment.topCenter,
                          ),
                        ),
                        padding: EdgeInsets.symmetric(
                            vertical: 10.0, horizontal: 20.0),
                        child: Text(
                          'No. ${imgList.indexOf(item)} image',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 20.0,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                    ),
                  ],
                )),
          ),
        ))
    .toList();

class ComplicatedImageDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CarouselSlider(
      options: CarouselOptions(
        autoPlay: true,
        aspectRatio: 2.0,
        enlargeCenterPage: true,
      ),
      items: imageSliders,
    );
  }
}