fluent_ui icon indicating copy to clipboard operation
fluent_ui copied to clipboard

🐛 TabView does not keep state on reorder or tab change

Open karamba121 opened this issue 2 years ago • 2 comments

Describe the bug When a Tab is clicked, the state of content in another tab in the same TabView resets to initial state

To Reproduce

import 'package:fluent_ui/fluent_ui.dart';

void main() {
  runApp(const TestPage());
}

class TestPage extends StatefulWidget {
  const TestPage({super.key});

  @override
  State<TestPage> createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  int currentIndex = 0;
  @override
  Widget build(BuildContext context) {
    return FluentApp(
      home: TabView(
        currentIndex: currentIndex,
        onChanged: (value) => setState(() {
          currentIndex = value;
        }),
        tabs: [
          Tab(text: const Text('test 1'), body: const CounterPage()),
          Tab(text: const Text('test 2'), body: const CounterPage()),
          Tab(text: const Text('test 3'), body: const CounterPage()),
        ],
      ),
    );
  }
}

class CounterPage extends StatefulWidget {
  const CounterPage({super.key});

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int counter = 0;

  void increment(){
    setState(() {
      counter++;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      Text('$counter'),
      Button(onPressed: increment, child: const Text('increment'))
    ],);
  }
}

Expected behavior When a Tab is clicked, the state of content in previous edited tab still the same

karamba121 avatar Aug 08 '23 08:08 karamba121

With some research, I found a workaround. Maybe it's good to incorporate to behavior of a TabView in this Lib.

Based on post from Diego Velasquez, at https://medium.com/@diegoveloper/flutter-persistent-tab-bars-a26220d322bc, Here it goes:

import 'package:fluent_ui/fluent_ui.dart';

void main() {
  runApp(const TestPage());
}

class TestPage extends StatefulWidget {
  const TestPage({super.key});

  @override
  State<TestPage> createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  int currentIndex = 0;
  @override
  Widget build(BuildContext context) {
    return FluentApp(
      home: TabView(
        currentIndex: currentIndex,
        onChanged: (value) => setState(() {
          currentIndex = value;
        }),
        tabs: [
          Tab(text: const Text('test 1'), body: const CounterPage()),
          Tab(text: const Text('test 2'), body: const CounterPage()),
          Tab(text: const Text('test 3'), body: const CounterPage()),
        ],
      ),
    );
  }
}

class CounterPage extends StatefulWidget {
  const CounterPage({super.key});

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> with AutomaticKeepAliveClientMixin<CounterPage> {
  int counter = 0;

  void increment(){
    setState(() {
      counter++;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      Text('$counter'),
      Button(onPressed: increment, child: const Text('increment'))
    ],);
  }

  
  @override
  bool get wantKeepAlive => true;
}

just add the "AutomaticKeepAliveClientMixin" in the state of stateful widget and override the "wantKeepAlive" property to "true", boom! the magic it did.

Thanks in advance, the post from Diego Velasquez and the fluent_ui by itself is the most incredible thing that I see in flutter in the last years.

PS: I'm brazilian and my english maybe is not the best, forgive me by the prose, please.

karamba121 avatar Aug 11 '23 03:08 karamba121

TabView uses PageView under the hood, which doesn't support the automatic usage of KeepAlives, like list view or sliver lists do. It is up to the developer to add it, via AutomaticKeepAliveClientMixin, since adding it automatically including it can lead to several performance problems.

In case of usage of go_router, one can use StatefulShellRoute to keep the state of the routes. Another options are also available, such as page storage.

bdlukaa avatar Aug 12 '23 21:08 bdlukaa