I have spent many hours researching this issue.
There are similar threads but I don’t think it is the same situation, so let me ask you a question.
What I want to do is use TabControler within the HookConsumerWidget to add a tab when the plus button is clicked and go to the last tab added.
But on startup and when the plus button is clicked I am getting the following error:
Controller’s length property (0) does not match the number of tabs (3)
present in TabBar’s tabs property.
- 3 is the number of times the plus button is clicked.
The controller length does not seem to change from zero.
Here is the code:
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class SampleListNotifier extends StateNotifier<List<String>> {
SampleListNotifier() : super(<String>[]);
// 値の操作を行う
void createSample(String title) {
state = [...state, title];
}
}
final sampleListProvider = StateNotifierProvider<SampleListNotifier, List<String>>(
(ref) => SampleListNotifier(),
);
class CustomTabController extends HookConsumerWidget {
const CustomTabController({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final samples = ref.watch(sampleListProvider);
final controller = useTabController(initialLength: samples.length);
final index = useState(samples.length);
final key = GlobalKey();
controller.addListener(() {
index.value = controller.index;
});
return Scaffold(
appBar: AppBar(
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.add),
onPressed: () async {
const result = 'test';
if (result?.isNotEmpty ?? true) {
ref.read(sampleListProvider.notifier).createSample(result!);
controller.animateTo(samples.length-1);
}
}),
title: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TabBar(
onTap: (index) {},
controller: controller,
isScrollable: true,
tabs: samples
.map((String sample) => Tab(text: sample))
.toList(),
),
],
),
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () async {
print('pressed!');
},
),
],
),
body: TabBarView(
key: key,
controller: controller,
children: samples
.map((String sample) =>
TabPage(key: UniqueKey() , title: sample))
.toList(),
),
);
}
}
class TabPage extends StatelessWidget {
const TabPage({required Key key, required this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Center(
child: Text(title)
);
}
}
Thanks in advance.
2
Answers
I have been struggling with this for a long time and finally solved it. I am not sure yet if this is the right way to do it. Thank you very much for those who responded.
But if anyone else has the same problem, please check this out. Also, if you have any problems with this method, please let me know.
I changed to flutter_riverpod instead of flutter_hook during the solution.
Add Loader i.e CircularProgressIndicator() instead of Tabbar and TabBarView at the time of adding new tab into the list. then call controller.animateTo(samples.length-1) after loader stops