flutter_carousel_slider icon indicating copy to clipboard operation
flutter_carousel_slider copied to clipboard

Prevent items for re-creating

Open scaraux opened this issue 4 years ago • 11 comments

I am passing a List of items to the Carousel Slider.

However I can notice that when moving from one cell to another, and going back and forth, the Widgets are being initState-ed and dispose-ed all the time. Is there a way to prevent this reloading behavior ?

scaraux avatar Jul 28 '20 18:07 scaraux

Are they Stateful or Stateless widgets?

jacksonw765 avatar Nov 30 '20 21:11 jacksonw765

I am having the same issue. I am using a Stateless Widget and the stacked plugin to implement it the MVVM way.

class LoginRegisterView extends StatelessWidget {
  final List<Widget> _views = <Widget>[
    LoginView(),
    RegisterView(),
  ];

  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<LoginRegisterViewModel>.reactive(
      viewModelBuilder: () => new LoginRegisterViewModel(),
      builder: (context, model, child) => Scaffold(
        body: Stack(
          children: <Widget>[
            Container(
              child: CarouselSlider(
                items: _views,
                options: CarouselOptions(
                  initialPage: 0,
                  height: double.infinity,
                ),
              ),
            ),
...
class LoginView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<LoginViewModel>.reactive(
      viewModelBuilder: () => new LoginViewModel(
        dialogWrapper: GetIt.I.get(),
        navigationService: GetIt.I.get(),
        localAuthService: GetIt.I.get(),
        loginExecutor: GetIt.I.get(),
        employeesExecutor: GetIt.I.get(),
        localStorageService: GetIt.I.get(),
        secureStorageService: GetIt.I.get(),
      ),
      builder: (context, model, child) => Scaffold( ...

Every time I swipe to an other view, it rebuilds, and with it, a new instance of the ViewModel is created. I think there is no need to rebuild it.

Also if I create the ViewModel as a variable and assign it inside the ViewModelBuilder, I get an exception, that the model is already disposed and cannot be assigned

DirtyNative avatar Dec 07 '20 11:12 DirtyNative

I have the same issue. The widget tree below contains a stateful widget. I also tried to set a key in the top level widget, however, the state is erased on sliding back and fourth. How can I preserve the state?

shangl avatar Dec 08 '20 20:12 shangl

In case other people run into the same problem, here is the solution:

You can indicate to flutter to keep the state by adding "with AutomaticKeepAliveClientMixin<PainTarget>" to the state you want to preserve. Additionally, you need to tell flutter explicitly to keep a certain state instance by overriding the method

@override bool get wantKeepAlive => true;

Unfortunately this will not lead to the state being preserved for infinite swiping, but swiping back will work perfectly fine.

shangl avatar Dec 08 '20 22:12 shangl

In case other people run into the same problem, here is the solution:

You can indicate to flutter to keep the state by adding "with AutomaticKeepAliveClientMixin" to the state you want to preserve. Additionally, you need to tell flutter explicitly to keep a certain state instance by overriding the method

@override bool get wantKeepAlive => true;

Unfortunately this will not lead to the state being preserved for infinite swiping, but swiping back will work perfectly fine.

Could you provide us the full code?

I tried it but it not worked.

Thanks

simo9900 avatar Dec 09 '20 23:12 simo9900

I am having the issue. @shangl can you provide the code as reference?

tyfoo1603 avatar Dec 13 '20 15:12 tyfoo1603

Thanks @shangl for providing this workaround. After infinite swipe the widget is recreated and the state is gone. Do you have a workaround for this?

This bug is very annoying inside flutter_carousel_slider. There are other open issues reporting the same behavior (e.g. https://github.com/serenader2014/flutter_carousel_slider/issues/315 )

alibasta avatar Feb 18 '22 15:02 alibasta

i am having the same issue, all components on my screen was rebuilding due to this package TAT

iEricKoh avatar May 19 '22 16:05 iEricKoh

For me the problem was that I was calling setState inside onPageChanged in CarouselOptions, I refactored the state outside using the provider pattern.

andreasgarvik avatar Feb 08 '23 17:02 andreasgarvik

In case other people run into the same problem, here is the solution:

You can indicate to flutter to keep the state by adding "with AutomaticKeepAliveClientMixin" to the state you want to preserve. Additionally, you need to tell flutter explicitly to keep a certain state instance by overriding the method

@OverRide bool get wantKeepAlive => true;

Unfortunately this will not lead to the state being preserved for infinite swiping, but swiping back will work perfectly fine.

There is also workaround if you want InfiniteScroll, but in that case you need to do all custom: set autoplay to false, set enableInfiniteScroll to false, customTimer for autoplay and use this method instead of just carouselController.nextPage: void customNextPage() { if (_pageIndex == carouselWidgets.length) { carouselController.animateToPage( 0, curve: Curves.fastOutSlowIn, ); } else { carouselController.nextPage( curve: Curves.fastOutSlowIn, ); } }

Merculiar avatar Sep 08 '23 16:09 Merculiar

@simo9900 @tyfoo1603

I'm not sure if you all are still experiencing this issue, but I also found it quite challenging. Here is my solution utilizing AutomaticKeepAliveClientMixin and wantKeepAlive as @shangl suggested:

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

  @override
  Widget build(BuildContext context) {
    return const CustomCarousel(
      carouselItems: [
        CarouselItem(name: 'Text 1'),
        CarouselItem(name: 'Text 2'),
        CarouselItem(name: 'Text 3'),
      ],
    );
  }
}

class CustomCarousel extends StatelessWidget {
  const CustomCarousel({
    super.key,
    required this.carouselItems,
  });

  final List<Widget> carouselItems;

  @override
  Widget build(BuildContext context) {
    return CarouselSlider.builder(
      options: CarouselOptions(
        initialPage: 0,
        scrollDirection: Axis.horizontal,
        onPageChanged: (index, reason) {},
      ),
      itemCount: carouselItems.length,
      itemBuilder: (context, index, realIndex) => carouselItems[index],
    );
  }
}

class CarouselItem extends StatefulWidget {
  const CarouselItem({super.key, required this.name});

  final String name;

  @override
  State<StatefulWidget> createState() => _CarouselItemState();
}

class _CarouselItemState extends State<CarouselItem> with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Center(
      child: Text(widget.name),
    );
  }

  @override
  bool get wantKeepAlive => true; // Ensures the state is kept alive.
}

kobars avatar Feb 12 '24 05:02 kobars