flutter_carousel_slider
flutter_carousel_slider copied to clipboard
Prevent items for re-creating
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 ?
Are they Stateful or Stateless widgets?
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
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?
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.
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
I am having the issue. @shangl can you provide the code as reference?
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 )
i am having the same issue, all components on my screen was rebuilding due to this package TAT
For me the problem was that I was calling setState inside onPageChanged in CarouselOptions, I refactored the state outside using the provider pattern.
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, ); } }
@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.
}