Skip to content

Instantly share code, notes, and snippets.

@Andrious
Last active March 8, 2024 02:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Andrious/cf3bc3ebe5463054fb320938b7853553 to your computer and use it in GitHub Desktop.
Save Andrious/cf3bc3ebe5463054fb320938b7853553 to your computer and use it in GitHub Desktop.
Two Screens with Three Counters and Print() functions highlight the StatefulWidgets' lifecycle
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
/// Highlights UI while debugging.
import 'package:flutter/rendering.dart' as debug;
void main() => runApp(MyApp());
///
class MyApp extends StatelessWidget {
///
MyApp({super.key}) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> MyApp StatelessWidget created. Its constructor called.');
}
}
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> MyApp build() called!');
}
/// Set some of these to true and see what happens.
/// They're only available in 'debug mode'.
/// They're to help during development
assert(() {
/// Highlights UI while debugging.
debug.debugPaintSizeEnabled = false;
debug.debugPaintBaselinesEnabled = false;
debug.debugPaintPointersEnabled = false;
debug.debugPaintLayerBordersEnabled = false;
debug.debugRepaintRainbowEnabled = false;
debug.debugRepaintTextRainbowEnabled = false;
return true;
}());
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: HomePage(),
);
}
}
///
class HomePage extends StatefulWidget {
///
HomePage({super.key}) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> HomePage StatefulWidget created. Its constructor called.');
}
}
@override
State createState() {
return HomePageState();
}
}
class HomePageState extends State<HomePage> with CounterState {
HomePageState() : super() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> HomePageState created. Its constructor called.');
}
}
@override
void initState() {
super.initState();
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> HomePageState initState() called.');
}
// Take in this State object into this class object
StateController(this);
}
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> HomePageState build() called!');
}
return FirstPage();
return const _FirstPageWithConst();
return FirstPage(key: UniqueKey());
return _InheritedWidget(child: const _FirstPageInherited());
return const _InheritedWidget(child: _FirstPageInherited());
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> HomePageState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
/// Called if the widget is 'moved' around the Widget tree
/// or when the State object is to be disposed() called.
@override
void deactivate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> HomePageState deactivate() called.');
}
super.deactivate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> HomePageState reassemble() called.');
}
super.reassemble();
}
}
///
/// First Page
///
///
///
class FirstPage extends StatefulWidget {
///
const FirstPage({super.key});
@override
State createState() {
return FirstPageState();
}
}
///
class FirstPageState extends State<FirstPage> with CounterState {
///
FirstPageState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState created. Its constructor called.');
}
}
@override
void initState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState initState() called.');
}
super.initState();
// HomePageState is found because its an ancestor on the same branch of the Widget tree.
homePageState = context.findAncestorStateOfType<HomePageState>()!;
}
///
late HomePageState homePageState;
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState build() called!');
}
return Scaffold(
appBar: AppBar(
title: Text('Home counter: ${homePageState.counter}'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FirstCounter(),
// const FirstCounter(), // See the difference!
const SizedBox(height: 100),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState button pressed. Its setState() called.');
}
setState(() {
counter++;
});
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
persistentFooterAlignment: AlignmentDirectional.centerStart,
persistentFooterButtons: <Widget>[
TextButton(
child: const Text(
'Title Counter',
),
onPressed: () {
//
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
">>>>>>>>>>>>>>>>>>>>>>>>> 'Title Counter' button pressed. _MyHomePageState setState() called.");
}
homePageState.counter++;
homePageState.setState(() {});
},
),
TextButton(
child: const Text(
'Second Page',
),
onPressed: () async {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
">>>>>>>>>>>>>>>>>>>>>>>>> 'Second Page' button pressed. Navigator.push() called.");
}
await Navigator.push(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) => SecondPage(),
),
);
// Update the Title count!
setState(() {});
},
),
],
);
}
/// Called if the widget is 'moved' around the Widget tree
/// or when the State object is to be disposed() called.
@override
void deactivate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print('>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState deactivate() called.');
}
super.deactivate();
}
@override
void didUpdateWidget(FirstPage oldWidget) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState didUpdateWidget() called.');
}
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
@override
void activate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState activate() called.');
}
super.activate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState reassemble() called.');
}
super.reassemble();
}
@override
void dispose() {
super.dispose();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageState disposed() called. Counter was $counter');
}
}
}
///
/// The First Counter
///
///
class FirstCounter extends StatefulWidget {
///
const FirstCounter({super.key});
@override
State createState() {
return FirstCounterState();
}
}
///
class FirstCounterState extends State<FirstCounter> with CounterState {
///
FirstCounterState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState created. Its constructor called.');
}
}
@override
void initState() {
super.initState();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState initState() called.');
}
}
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState build() called!');
}
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: FloatingActionButton(
heroTag:
null, // Fixes 'multiple heroes that share the same tag' error
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState button pressed. Its setState() called.');
}
counter++;
setState(() {});
},
child: const Icon(Icons.add),
),
),
),
],
);
}
/// Called if the widget is 'moved' around the Widget tree
/// or when the State object is to be disposed() called.
@override
void deactivate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState deactivate() called.');
}
super.deactivate();
}
@override
void didUpdateWidget(FirstCounter oldWidget) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState didUpdateWidget() called.');
}
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
@override
void activate() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState activate() called.');
}
super.activate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState reassemble() called.');
}
super.reassemble();
}
@override
void dispose() {
super.dispose();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterState disposed() called. Counter was $counter');
}
}
}
///
/// Second Page
///
///
class SecondPage extends StatefulWidget {
///
SecondPage({super.key}) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPage StatefulWidget created. Its constructor called.');
}
}
@override
State createState() {
return SecondPageState();
}
}
///
class SecondPageState extends State<SecondPage> with CounterState {
///
SecondPageState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState created. Its constructor called.');
}
}
@override
void initState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState initState() called.');
}
super.initState();
// Returns null.
// HomePageState is on a separate branch of the Widget tree.
homePageState = context.findAncestorStateOfType<HomePageState>();
homePageState = context.findRootAncestorStateOfType<HomePageState>();
// Supply access to the Home Page's State object.
con = StateController(this);
}
///
HomePageState? homePageState;
///
late StateController con;
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState build() called!');
}
return Scaffold(
appBar: AppBar(
title: Text('Home counter: ${con.counter}'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text("You're on this second page."),
const Text('You have pushed the button this many times:'),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> Second page FloatingActionButton pressed. Its setState() called.');
}
setState(() {
counter++;
});
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
persistentFooterAlignment: AlignmentDirectional.centerStart,
persistentFooterButtons: <Widget>[
TextButton(
child: const Text(
'Title Counter',
),
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
">>>>>>>>>>>>>>>>>>>>>>>>> 'Title Counter' button pressed. SecondPageState setState() called.");
}
con.counter++;
setState(() {});
},
),
],
);
}
@override
void deactivate() {
super.deactivate();
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState deactivate() called.');
}
}
@override
void didUpdateWidget(SecondPage oldWidget) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState didUpdateWidget() called.');
}
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
@override
void activate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState activate() called.');
}
super.activate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState reassemble() called.');
}
super.reassemble();
}
@override
void dispose() {
super.dispose();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState disposed() called. Counter was $counter');
}
}
}
///
/// FirstPage called with const keyword
///
///
///
class _FirstPageWithConst extends StatefulWidget {
///
const _FirstPageWithConst();
@override
State createState() {
return _FirstPageWithConstState();
}
}
///
class _FirstPageWithConstState extends State<_FirstPageWithConst>
with CounterState {
///
_FirstPageWithConstState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState created. Its constructor called.');
}
}
@override
void initState() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState initState() called.');
}
super.initState();
// HomePageState is found because its an ancestor on the same branch of the Widget tree.
homePageState = context.findAncestorStateOfType<HomePageState>()!;
}
late HomePageState homePageState;
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState build() called!');
}
return Scaffold(
appBar: AppBar(
title: Text('Home counter: ${homePageState.counter}'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const _FirstCounterWithConst(),
const SizedBox(height: 100),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState button pressed. Its setState() called.');
}
setState(() {
counter++;
});
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
persistentFooterAlignment: AlignmentDirectional.centerStart,
persistentFooterButtons: <Widget>[
TextButton(
child: const Text(
'Title Counter',
),
onPressed: () {
//
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
">>>>>>>>>>>>>>>>>>>>>>>>> 'Title Counter' button pressed. _FirstPageConstState setState() called.");
}
homePageState.counter++;
setState(() {});
},
),
TextButton(
child: const Text(
'Second Page',
),
onPressed: () async {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
">>>>>>>>>>>>>>>>>>>>>>>>> 'Second Page' button pressed. Navigator.push() called.");
}
await Navigator.push(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) => SecondPage(),
),
);
// Update the Title count!
setState(() {}); // Comment out. Title count won't refresh.
},
),
],
);
}
/// Called if the widget is 'moved' around the Widget tree
/// or when the State object is to be disposed() called.
@override
void deactivate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState deactivate() called.');
}
super.deactivate();
}
@override
void didUpdateWidget(_FirstPageWithConst oldWidget) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState didUpdateWidget() called.');
}
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
@override
void activate() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState activate() called.');
}
super.activate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState reassemble() called.');
}
super.reassemble();
}
@override
void dispose() {
super.dispose();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageWithConstState disposed() called. Counter was $counter');
}
}
}
///
/// FirstCounter called with the const keyword
///
///
class _FirstCounterWithConst extends StatefulWidget {
///
const _FirstCounterWithConst();
@override
State createState() {
return _FirstCounterWithConstState();
}
}
///
class _FirstCounterWithConstState extends State<_FirstCounterWithConst>
with CounterState {
///
_FirstCounterWithConstState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState created. Its constructor called.');
}
}
@override
void initState() {
super.initState();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState initState() called.');
}
}
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState build() called!');
}
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: FloatingActionButton(
heroTag:
null, // Fix 'multiple heroes that share the same tag' error
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState button pressed.');
}
counter++;
setState(() {});
},
child: const Icon(Icons.add),
),
),
),
],
);
}
/// Called if the widget is 'moved' around the Widget tree
/// or when the State object is to be disposed() called.
@override
void deactivate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState deactivate() called.');
}
super.deactivate();
}
@override
void didUpdateWidget(_FirstCounterWithConst oldWidget) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState didUpdateWidget() called.');
}
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
@override
void activate() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState activate() called.');
}
super.activate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState reassemble() called.');
}
super.reassemble();
}
@override
void dispose() {
super.dispose();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterWithConstState disposed() called. Counter was $counter');
}
}
}
///
/// FirstPage called with const keyword
/// and indirectly involving an InheritedWidget
///
///
///
class _FirstPageInherited extends StatefulWidget {
///
const _FirstPageInherited();
@override
State createState() {
return _FirstPageInheritedState();
}
}
///
/// FirstPageState indirectly involving an InheritedWidget
///
///
class _FirstPageInheritedState extends State<_FirstPageInherited>
with CounterState {
///
_FirstPageInheritedState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState created. Its constructor called.');
}
}
@override
void initState() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState initState() called.');
}
super.initState();
// HomePageState is found because its an ancestor on the same branch of the Widget tree.
homePageState = context.findAncestorStateOfType<HomePageState>()!;
}
late HomePageState homePageState;
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState build() called!');
}
return Scaffold(
appBar: AppBar(
title: const HomeTitle(),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const _FirstCounterInherited(),
const SizedBox(height: 100),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState button pressed. Its setState() called.');
}
setState(() {
counter++;
});
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
persistentFooterAlignment: AlignmentDirectional.centerStart,
persistentFooterButtons: <Widget>[
TextButton(
child: const Text(
'Title Counter',
),
onPressed: () {
//
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
">>>>>>>>>>>>>>>>>>>>>>>>> 'Title Counter' button pressed. _FirstPageInheritedState setState() called.");
}
homePageState.counter++;
// Commented out, going back to the First Page, title counter not displayed correctly.
homePageState.setState(() {});
// It's incremented, and change displayed here
// setState(() {});
},
),
TextButton(
child: const Text(
'Second Page',
),
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
">>>>>>>>>>>>>>>>>>>>>>>>> 'Second Page' button pressed. Navigator.push() called.");
}
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) => _SecondPageInherited(),
),
);
},
),
],
);
}
/// Called if the widget is 'moved' around the Widget tree
/// or when the State object is to be disposed() called.
@override
void deactivate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState deactivate() called.');
}
super.deactivate();
}
@override
void didUpdateWidget(_FirstPageInherited oldWidget) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState didUpdateWidget() called.');
}
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
@override
void activate() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState activate() called.');
}
super.activate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState reassemble() called.');
}
super.reassemble();
}
@override
void dispose() {
super.dispose();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstPageInheritedState disposed() called. Counter was $counter');
}
}
}
//
/// FirstCounter called with the const keyword
/// and involving an InheritedWidget
///
///
class _FirstCounterInherited extends StatefulWidget {
///
const _FirstCounterInherited();
@override
State createState() {
return _FirstCounterInheritedState();
}
}
///
/// FirstCounterState indirectly calling an InheritedWidget
///
///
class _FirstCounterInheritedState extends State<_FirstCounterInherited>
with CounterState {
///
_FirstCounterInheritedState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState created. Its constructor called.');
}
}
@override
void initState() {
super.initState();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState initState() called.');
}
// HomePageState is found because its an ancestor on the same branch of the Widget tree.
homePageState = context.findAncestorStateOfType<HomePageState>()!;
}
late HomePageState homePageState;
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState build() called!');
}
// _InheritedWidget is found because its an ancestor on the same branch
// as this State object on the Widget tree.
context.dependOnInheritedWidgetOfExactType<_InheritedWidget>();
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: FloatingActionButton(
heroTag:
null, // Fix 'multiple heroes that share the same tag' error
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState button pressed.');
}
counter++;
// Calling HomePageState to rebuild will call the InheritedWidget
// _InheritedWidget if it's implemented there.
// And because this State object called,
// dependOnInheritedWidgetOfExactType<_InheritedWidget>(),
// this State object will also rebuild!! Cool!
homePageState.setState(() {});
// What does this do all alone?
// setState(() {});
},
child: const Icon(Icons.add),
),
),
),
],
);
}
/// Called if the widget is 'moved' around the Widget tree
/// or when the State object is to be disposed() called.
@override
void deactivate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState deactivate() called.');
}
super.deactivate();
}
@override
void didUpdateWidget(_FirstCounterInherited oldWidget) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState didUpdateWidget() called.');
}
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
@override
void activate() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState activate() called.');
}
super.activate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState reassemble() called.');
}
super.reassemble();
}
@override
void dispose() {
super.dispose();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> _FirstCounterInheritedState disposed() called. Counter was $counter');
}
}
}
///
/// Second Page involving an InheritedWidget
///
///
class _SecondPageInherited extends StatefulWidget {
_SecondPageInherited() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPage StatefulWidget created. Its constructor called.');
}
}
@override
State createState() {
return _SecondPageInheritedState();
}
}
class _SecondPageInheritedState extends State<_SecondPageInherited>
with CounterState {
_SecondPageInheritedState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState created. Its constructor called.');
}
}
@override
void initState() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState initState() called.');
}
super.initState();
// Supply access to the Home Page's State object.
con = StateController(this);
}
HomePageState? homePageState;
late StateController con;
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState build() called!');
}
return Scaffold(
appBar: AppBar(
title: Text('Home counter: ${con.counter}'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text("You're on this second page."),
const Text('You have pushed the button this many times:'),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> Second page FloatingActionButton pressed. Its setState() called.');
}
setState(() {
counter++;
});
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
persistentFooterAlignment: AlignmentDirectional.centerStart,
persistentFooterButtons: <Widget>[
TextButton(
child: const Text(
'Title Counter',
),
onPressed: () {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print(
">>>>>>>>>>>>>>>>>>>>>>>>> 'Title Counter' button pressed. SecondPageState setState() called.");
}
con.counter++;
con.setState(() {}); // Update count on First Page screen
setState(() {}); // Update count in this screen
},
),
],
);
}
@override
void deactivate() {
super.deactivate();
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>>');
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState deactivate() called.');
}
}
@override
void didUpdateWidget(_SecondPageInherited oldWidget) {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState didUpdateWidget() called.');
}
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState didChangeDependencies() called.');
}
super.didChangeDependencies();
}
@override
void activate() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState activate() called.');
}
super.activate();
}
/// Called during a 'hot reload'
@override
void reassemble() {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState reassemble() called.');
}
super.reassemble();
}
@override
void dispose() {
super.dispose();
if (kDebugMode) {
print(
'>>>>>>>>>>>>>>>>>>>>>>>>> SecondPageState disposed() called. Counter was $counter');
}
}
}
///
/// A StatelessWidget made a dependent to an InheritedWidget
///
///
class HomeTitle extends StatelessWidget {
///
const HomeTitle({super.key});
@override
Widget build(BuildContext context) {
if (kDebugMode) {
print('>>>>>>>>>>>>>>>>>>>>>>>>> HomeTitle build() called!');
}
// _InheritedWidget is found because its an ancestor on the same branch on the Widget tree.
// You don't have to take in the return InheritedWidget. It's there just for demonstration purposes.
// ignore: unused_local_variable
final inheritedWidget =
context.dependOnInheritedWidgetOfExactType<_InheritedWidget>();
final homePageState = context.findAncestorStateOfType<HomePageState>();
String title;
if (homePageState == null) {
title = 'Home Page';
} else {
title = 'Home counter: ${homePageState.counter}';
}
return Text(title);
}
}
///
/// A simple means to 'preserves state' but spans between Navigator's screens
///
///
class StateController implements State, CounterState {
/// Must pass a State object but only the first one is saved.
/// Any other will be ignored.
factory StateController(CounterState state) =>
_this ??= StateController._(state);
StateController._(CounterState state) {
_state = state;
}
static StateController? _this;
///
CounterState get state => _state;
late CounterState _state;
@override
void activate() {}
@override
Widget build(BuildContext context) => _state.build(context);
@override
BuildContext get context => _state.context;
@override
void deactivate() {}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
@override
void didChangeDependencies() {}
@override
void didUpdateWidget(covariant StatefulWidget oldWidget) {}
@override
void dispose() {}
@override
void initState() {}
@override
bool get mounted => _state.mounted;
/// Called when a hot reload is performed.
@override
void reassemble() {}
@override
void setState(VoidCallback fn) => _state.setState(fn);
@override
DiagnosticsNode toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) =>
_state.toDiagnosticsNode(name: name, style: style);
@override
String toStringShort() => _state.toStringShort();
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) =>
_state.toString(minLevel: minLevel);
@override
StatefulWidget get widget => _state.widget;
@override
int get counter => _state.counter;
@override
set counter(int counter) {
if (counter == _state.counter + 1) {
_state.counter++;
}
}
}
/// Mixin contains a counter
mixin CounterState<T extends StatefulWidget> on State<T> {
///
int counter = 0;
}
class _InheritedWidget extends InheritedWidget {
const _InheritedWidget({required super.child});
// _InheritedWidget({required super.child}); // Better to remove the const keyword
@override
bool updateShouldNotify(_InheritedWidget oldWidget) => true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment