Add an `index` to `DefaultTabController` to control active tab declaratively
- Dominant language
- Dart
- Stars
- 179k
- Forks
- 31.1k
- PR merge metrics
- PR metrics pending
Description
### Steps to reproduce
this issue (https://github.com/flutter/flutter/issues/167169) is related but was closed
just run the following codesample
install latest riverpod and run it on android.
### Expected results
the tab visualization should show that the index has changed
### Actual results
When you press the button as in the video you can see that the tab will not change the index, although the value for initialIndex has changed
### Code sample
Code sample
```dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(
ProviderScope(
child: DebugApp(),
),
);
}
class Counter extends Notifier {
@override
int build() => 0;
void increment() => state = (state + 1) % 2;
void set(int value) => state = value % 2;
}
final counter = NotifierProvider(Counter.new);
class DebugApp extends ConsumerWidget {
const DebugApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
var index = ref.watch(counter);
return MaterialApp(
home: Material(
child: DefaultTabController(
length: 2,
initialIndex: index,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
tabs: List.generate(2, (i) =>
SizedBox(height: 100,width:100, child: Tab(child: Text("$i")))),
onTap: (index) => ref.read(counter.notifier).set(index),
),
OutlinedButton(
onPressed: ref
.read(counter.notifier)
.increment,
child: Text("Current Index $index",),
),
],
),
),
),
);
}
}
```
### Screenshots or Video
Screenshots / Video demonstration
[[Upload media here]](https://github.com/user-attachments/assets/f9e4a7fd-6e3b-418c-bdcd-7d06ff4070c5)
### Logs
Logs
```console
Syncing files to device SM G981B...
I/ViewRootImpl(18984): updatePointerIcon pointerType = 1000, calling pid = 18984
Restarted application in 1.241ms.
D/InputManager(18984): setPointerIconType iconId = 1000, callingPid = 18984
I/ViewRootImpl(18984): updatePointerIcon pointerType = 1000, calling pid = 18984
D/InputManager(18984): setPointerIconType iconId = 1000, callingPid = 18984
I/Choreographer(18984): Skipped 101 frames! The application may be doing too much work on its main thread.
I/ViewRootImpl(18984): updatePointerIcon pointerType = 1000, calling pid = 18984
D/InputManager(18984): setPointerIconType iconId = 1000, callingPid = 18984
I/ViewRootImpl(18984): updatePointerIcon pointerType = 1000, calling pid = 18984
D/InputManager(18984): setPointerIconType iconId = 1000, callingPid = 18984
```
### Flutter Doctor output
Doctor output
```console
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.38.5, on Microsoft Windows [Version 10.0.26200.7462], locale de-DE)
[√] Windows Version (11 Home 64-bit, 25H2, 2009)
[√] Android toolchain - develop for Android devices (Android SDK version 36.1.0-rc1)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.14.14)
[√] Connected device (4 available)
! Device emulator-5562 is offline.
[√] Network resources
• No issues found!
```
Contributor guide
Research direction
Start with the provided main() reproduction and the related issue 167169, running the sample on Android to observe how changing initialIndex affects DefaultTabController. Trace the existing DefaultTabController behavior and decide how a declarative index should control the active tab; done means the displayed tab changes when the external index changes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, dart, flutter
- Domain
- mobile-dev
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100