I created a StateProvider:
final tabsStateProvider = StateNotifierProvider<TabsProvider, List<TabClass>>(
(ref) => TabsProvider());
and I’m listening to it with ref.listen
:
Inside ref.listen
, when the state changes, I’m calling tabController.animateTo(1);
but it’s not having any effect on the tabs. I’m not sure why.
I added a print statement in the ref.listen
which gets called but tabController.animateTo(1);
in particular is not getting called for some reason.
My class code:
class HomePage extends ConsumerStatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
HomePageState createState() => HomePageState();
}
class HomePageState extends ConsumerState<HomePage>
with TickerProviderStateMixin {
late TabController tabController;
@override
Widget build(BuildContext context) {
List<TabClass> tabClassList = ref.watch(tabsStateProvider);
TabsProvider tabsProvider = ref.watch(tabsStateProvider.notifier);
tabController =
TabController(length: ref.watch(tabsStateProvider).length, vsync: this);
ref.listen(tabsStateProvider, (previousState, latestState) {
debugPrint('TAB STATE -> $latestState');
tabController.animateTo(1);
});
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: DottedBorder(
color: Colors.black,
strokeWidth: 1,
dashPattern: const [5, 5],
child: Row(
children: [
const Flexible(
child: Text(
'Create',
style: TextStyle(fontSize: 20),
),
),
],
),
),
),
Expanded(
child: DefaultTabController(
length: tabClassList.length,
child: Column(
children: [
SizedBox(
height: 60,
child: AppBar(
bottom: TabBar(
controller: tabController,
isScrollable: true,
tabs: List.generate(
tabClassList.length,
(index) {
TabClass tabClass = tabClassList[index];
return Row(
mainAxisSize: MainAxisSize.min,
children: [
TitleWidget(title: tabClass.tabsTitle),
index != 0
? InkWell(
onTap: () {
tabsProvider.decrement(index);
},
child:
Icon(Icons.close, color: Colors.red),
)
: SizedBox.shrink(),
],
);
},
),
),
),
),
Expanded(
child: TabBarView(
controller: tabController,
children:
tabClassList.map((e) => e.tabBarViewWidget).toList()),
),
],
),
),
),
],
);
}
}
I expected the tab to animate to the second tab which is position 1.
This is my state class:
final tabsStateProvider = StateNotifierProvider<TabsProvider, List<TabClass>>(
(ref) => TabsProvider());
class TabsProvider extends StateNotifier<List<TabClass>> {
TabsProvider()
: super([
TabClass(tabsTitle: 'Tab 1', tabBarViewWidget: TabBarViewWidget())
]);
void increment() => state = [
...state,
TabClass(
tabsTitle: 'Tab ${state.length + 1}',
tabBarViewWidget: TabBarViewWidget())
];
void decrement(int index) => state = [
for (final tab in state)
if (tab.tabsTitle != state[index].tabsTitle) tab
];
}
class TabClass {
final String tabsTitle;
final TabBarViewWidget tabBarViewWidget;
TabClass({required this.tabsTitle, required this.tabBarViewWidget});
}
2
Answers
Your
TabClass
objects must be immutable and have allfinal
fields. Moreover, yourList<TabClass>
must be modified using theList.of(...)
orstate = [...state]
method to change your state inTabsProvider
.tabController.animateTo(1) : This is calling but widget is not updating . There is difference between ref.watch and ref.listen. Due to this the controller’s tab is not changing its positions .
ref.listen:-
The main difference between them is that, rather than rebuilding the widget/provider if the listened to provider changes, using ref.listen will instead call a custom function.
That can be useful for performing actions when a certain change happens, such as showing a snackbar when an error happens.
The ref.listen method needs 2 positional arguments, the first one is the Provider and the second one is the callback function that we want to execute when the state changes. The callback function when called will be passed 2 values, the value of the previous State and the value of the new State.
The ref.listen method can be used inside the body of a provider.
It is better to use for showing error message, Navigation,print , Scaffold etc.
Check this link for preference .
ref.listen() and ref.listen.
I have updated your code and it’s working now.