Preserving state between tab view pages in TabBar - error

Viewed 35

════════ Exception caught by widgets library ═══════════════════════════════════ The following assertion was thrown building KeyedSubtree-[<1>]: 'package:flutter/src/widgets/automatic_keep_alive.dart': Failed assertion: line 348 pos 12: '_keepAliveHandle == null': is not true.

class MyAppState extends State with AutomaticKeepAliveClientMixin{

@override bool get wantKeepAlive => true;

}

1 Answers

You can use IndexedStack widget instead, it's a stack but you control the outer widget using the index property

here is a usage example

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  int tab = 0;
  late final controller = TabController(length: 3, vsync: this);

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: IndexedStack(
          index: tab,
          children: [
            FutureBuilder(
                future: Future.delayed(const Duration(seconds: 3), () {
                  return 'Tab0, This should appear after 3 seconds';
                }),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Center(child: Text(snapshot.data.toString()));
                  }
                  return const Center(child: CircularProgressIndicator());
                }),
            FutureBuilder(
                future: Future.delayed(const Duration(seconds: 5), () {
                  return 'Tab1, This should appear after 5 seconds';
                }),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Center(child: Text(snapshot.data.toString()));
                  }
                  return const Center(child: CircularProgressIndicator());
                }),
            FutureBuilder(
                future: Future.delayed(const Duration(seconds: 10), () {
                  return 'Tab2, This should appear after 10 seconds';
                }),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Center(child: Text(snapshot.data.toString()));
                  }
                  return const Center(child: CircularProgressIndicator());
                }),
          ],
        ),
        bottomNavigationBar: Material(
          elevation: 16.0,
          child: TabBar(
            controller: controller,
            unselectedLabelColor: Colors.black,
            labelColor: Colors.blue,
            onTap: (index) {
              setState(() {
                tab = index;
              });
            },
            tabs: const [
              Tab(icon: Icon(Icons.category)),
              Tab(icon: Icon(Icons.home)),
              Tab(icon: Icon(Icons.list)),
            ],
          ),
        ),
      ),
    );
  }
}

Note, if your tabs does a network requests, all network requests will be requested unless you control them in the TabBar.onTap: (index){} method

Related