'Flutter - Page with SingleTickerProviderStateMixin cause unnecessary build
I am having this issue github link. What happens is if a widget uses TickerProviderStateMixin then it gets rebuilt when a page navigation occurs. I have a very complex page and rebuilding the whole page causes a UI jank on page navigation. If I do not rebuild then everything is fine no janks. Is there a workaround for this? It seems to me that this is some sort of an internal flutter bug or unexpected behaviour?
Example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PageA(title: 'Flutter Demo Home Page'),
);
}
}
class PageA extends StatefulWidget {
PageA({Key key, this.title}) : super(key: key);
final String title;
@override
_PageAState createState() => _PageAState();
}
class _PageAState extends State<PageA>
with SingleTickerProviderStateMixin {
TabController tabController;
@override
void initState() {
super.initState();
tabController = TabController(length: 2, vsync: this);
}
void toPageB() {
//tabController.animateTo(1);
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
return PageB();
}));
}
@override
Widget build(BuildContext context) {
print("Page A");
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: TabBar(
tabs: [
Text(
"Tab A",
style: Theme.of(context).textTheme.bodyText1,
),
Text(
"Tab B",
style: Theme.of(context).textTheme.bodyText1,
)
],
controller: tabController,
),
),
floatingActionButton: FloatingActionButton(
onPressed: toPageB,
child: Icon(Icons.add),
),
);
}
}
class PageB extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Page B");
return Scaffold(
appBar: AppBar(
title: Text("Page A"),
),
body: Container(
child: Center(
child: Text("Page A"),
),
));
}
}
Solution 1:[1]
@override
// ignore: must_call_super
void didChangeDependencies() {}
just add the code to prevent the rebuild, I dont know the side effect, but this walk around works for my app.
Solution 2:[2]
This is the solution I used before.
Change your Page A like
class PageA extends StatefulWidget {
PageA({Key key, this.title}) : super(key: key);
final String title;
@override
_PageAState createState() => _PageAState();
}
class _PageAState extends State<PageA> {
TabController tabController;
// @override
// void initState() {
// super.initState();
// tabController = TabController(length: 2, vsync: this);
// }
void toPageB() {
tabController.animateTo(1);
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
return PageB();
}));
}
@override
Widget build(BuildContext context) {
print("Page A");
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: CustomTabBar(
tabs: [
Text(
"Tab A",
style: Theme.of(context).textTheme.bodyText1,
),
Text(
"Tab B",
style: Theme.of(context).textTheme.bodyText1,
)
],
controller: (controller) {
tabController = controller;
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: toPageB,
child: Icon(Icons.add),
),
);
}
}
And add a new class CustomTabBar
class CustomTabBar extends StatefulWidget {
const CustomTabBar({
this.controller,
this.tabs,
Key? key,
}) : super(key: key);
final Function(TabController)? controller;
final List<Widget>? tabs;
@override
_CustomTabBarState createState() => _CustomTabBarState();
}
class _CustomTabBarState extends State<CustomTabBar>
with SingleTickerProviderStateMixin {
late TabController tabController;
@override
void initState() {
super.initState();
tabController =
TabController(length: widget.tabs?.length ?? 0, vsync: this);
if (widget.controller != null) {
widget.controller!(tabController);
}
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TabBar(
tabs: widget.tabs ?? [],
controller: tabController,
);
}
}
It should fix the issue that Page A rebuild
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | noname.cs |
Solution 2 | Adnan |