This repo contains all the downloadable materials and projects associated with the Managing State in Flutter from raywenderlich.com.
Each edition has its own branch, named versions/[VERSION]
. The default branch for this repo is for the most recent edition.
Branch | Version | Release Date |
---|---|---|
versions/2.0 | 2.0 | 2022-09-22 |
![image](https://private-user-images.githubusercontent.com/47273077/243150022-a982f158-67be-42ee-9c85-631aa5aedc89.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NTYzNjAsIm5iZiI6MTcyMTQ1NjA2MCwicGF0aCI6Ii80NzI3MzA3Ny8yNDMxNTAwMjItYTk4MmYxNTgtNjdiZS00MmVlLTljODUtNjMxYWE1YWVkYzg5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzIwVDA2MTQyMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWNhNTY2YTBlMmIwMDI0ZDFkZjk1OGJlNTE1YmQ2M2RiNDQyOTdlMTYzYzQ4YzMzMTFkZTY3OWMxNzM2ZjNkZDcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.RCrrhN_qGdHjFXQUI_XQ6XW1mI82nVAPkNSSxyaULdM)
lib/main.dart
void main() {
runApp(const Application());
}
class Application extends StatefulWidget {
const Application({super.key});
@override
State<Application> createState() => _ApplicationState();
}
class _ApplicationState extends State<Application> {
final pillarData = Pillar(type: PillarType.flutter, articleCount: 115);
late ValueNotifier<int> valueNoitifier;
@override
void initState() {
valueNoitifier = ValueNotifier<int>(pillarData.articleCount);
valueNoitifier.addListener(() {
setState(() {
final increaseAmount = valueNoitifier.value - pillarData.articleCount;
pillarData.increaseArticleCount(by: increaseAmount);
});
});
super.initState();
}
@override
void dispose() {
valueNoitifier.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tutorial Tracker',
theme: ThemeData(primarySwatch: Colors.green),
home: Scaffold(
appBar: AppBar(
title: const Text('Tutorial Tracker'),
),
body: TutorialsPage(
pillar: pillarData,
valueNotifier: valueNoitifier,
),
),
);
}
}
lib/pages/tutorials_page.dart
class TutorialsPage extends StatefulWidget {
final Pillar pillar;
final ValueNotifier<int> valueNotifier;
const TutorialsPage({
required this.pillar,
required this.valueNotifier,
super.key,
});
@override
State<TutorialsPage> createState() => _TutorialsPageState();
}
class _TutorialsPageState extends State<TutorialsPage> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: TutorialWidget(
pillar: widget.pillar,
valueNotifier: widget.valueNotifier,
),
),
Padding(
padding: const EdgeInsets.only(top: 24.0),
child: Text(
'Total Tutorials: ${widget.pillar.articleCount}',
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
)
],
);
}
}
lib/widgets/tutorial_widget.dart
class TutorialWidget extends StatefulWidget {
final Pillar pillar;
final ValueNotifier<int> valueNotifier;
const TutorialWidget({
required this.pillar,
required this.valueNotifier,
super.key,
});
@override
State<TutorialWidget> createState() => _TutorialWidgetState();
}
class _TutorialWidgetState extends State<TutorialWidget> {
@override
Widget build(BuildContext context) {
return Stack(
children: [
InkWell(
onTap: () {
setState(() {
widget.valueNotifier.value++;
});
},
child: Image.asset('assets/images/${widget.pillar.type.imageName}',
width: 110, height: 110),
),
Positioned(
bottom: 2,
child: CircleAvatar(
backgroundColor: Colors.blue,
child: Text(widget.pillar.articleCount.toString()),
),
)
],
);
}
}
lib/models/pillar.dart
class Pillar extends ValueNotifier<int>{
int get articleCount => value;
var active = true;
final PillarType type;
Pillar({required this.type, int articleCount = 10}) : super(articleCount);
void increaseArticleCount({int by = 1}) {
value += by;
}
}
lib/main.dart
class _ApplicationState extends State<Application> {
final pillarData = Pillar(type: PillarType.flutter, articleCount: 115);
@override
void dispose() {
pillarData.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tutorial Tracker',
theme: ThemeData(primarySwatch: Colors.green),
home: Scaffold(
appBar: AppBar(
title: const Text('Tutorial Tracker'),
),
body: ValueListenableBuilder(
valueListenable: pillarData,
builder: (context, value, child) {
return TutorialsPage(
pillar: pillarData,
);
}
),
),
);
}
}
lib/pages/tutorials_page.dart
class TutorialsPage extends StatefulWidget {
final Pillar pillar;
const TutorialsPage({
required this.pillar,
super.key,
});
@override
State<TutorialsPage> createState() => _TutorialsPageState();
}
class _TutorialsPageState extends State<TutorialsPage> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: TutorialWidget(
pillar: widget.pillar,
),
),
Padding(
padding: const EdgeInsets.only(top: 24.0),
child: Text(
'Total Tutorials: ${widget.pillar.articleCount}',
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
)
],
);
}
}
lib/widgets/tutorial_widget.dart
class TutorialWidget extends StatefulWidget {
final Pillar pillar;
const TutorialWidget({
required this.pillar,
super.key,
});
@override
State<TutorialWidget> createState() => _TutorialWidgetState();
}
class _TutorialWidgetState extends State<TutorialWidget> {
@override
Widget build(BuildContext context) {
return Stack(
children: [
InkWell(
onTap: () {
widget.pillar.increaseArticleCount();
},
child: Image.asset('assets/images/${widget.pillar.type.imageName}',
width: 110, height: 110),
),
Positioned(
bottom: 2,
child: CircleAvatar(
backgroundColor: Colors.blue,
child: Text(widget.pillar.articleCount.toString()),
),
)
],
);
}
}
lib/state/pillar_widget.dart
import 'package:flutter/material.dart';
import '../models/pillar.dart';
class PillarIhheritedWiget extends InheritedWidget {
final PillarState state;
final int articleCount;
const PillarIhheritedWiget(
{required this.articleCount, required this.state, super.key, required super.child});
static PillarState of(BuildContext context) {
final PillarIhheritedWiget? result =
context.dependOnInheritedWidgetOfExactType<PillarIhheritedWiget>();
assert(result != null, 'No PillarWidget found in context');
return result!.state;
}
@override
bool updateShouldNotify(PillarIhheritedWiget old) => articleCount != old.articleCount;
}
class PillarSttatefulWidget extends StatefulWidget {
final Widget child;
final Pillar pillarData;
const PillarSttatefulWidget(
{required this.pillarData, required this.child, Key? key})
: super(key: key);
@override
State<PillarSttatefulWidget> createState() => PillarState();
}
class PillarState extends State<PillarSttatefulWidget> {
get articleCount => widget.pillarData.articleCount;
get imageName => widget.pillarData.type.imageName;
void increaseArticleCount({ int by = 1}) {
setState(() {
widget.pillarData.increaseArticleCount(by: by);
});
}
@override
Widget build(BuildContext context) {
return PillarIhheritedWiget(
articleCount: articleCount,
state: this,
child: widget.child,
);
}
}
lib/models/pillar.dart
import 'package:flutter/material.dart';
class Pillar {
var _articleCount = 0;
int get articleCount => _articleCount;
var active = true;
final PillarType type;
Pillar({required this.type, int articleCount = 10}) {
_articleCount = articleCount;
}
void increaseArticleCount({int by = 1}) {
_articleCount += by;
}
}
enum PillarType {
flutter('flutter.png', Colors.blue),
android('android.png', Colors.green),
ios('ios.png', Colors.orange);
final String imageName;
final Color backgroundColor;
const PillarType(this.imageName, this.backgroundColor);
}
lib/main.dart
import 'package:flutter/material.dart';
import 'pages/tutorials_page.dart';
import 'models/pillar.dart';
import 'state/pillar_widget.dart';
void main() {
runApp(const Application());
}
class Application extends StatefulWidget {
const Application({super.key});
@override
State<Application> createState() => _ApplicationState();
}
class _ApplicationState extends State<Application> {
final pillarData = Pillar(type: PillarType.flutter, articleCount: 115);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tutorial Tracker',
theme: ThemeData(primarySwatch: Colors.green),
home: Scaffold(
appBar: AppBar(
title: const Text('Tutorial Tracker'),
),
body: PillarSttatefulWidget(
pillarData: pillarData,
child: const TutorialsPage(),
),
),
);
}
}
lib/pages/tutorials_page.dart
import 'package:flutter/material.dart';
import '../widgets/tutorial_widget.dart';
import '../state/pillar_widget.dart';
class TutorialsPage extends StatefulWidget {
const TutorialsPage({
super.key,
});
@override
State<TutorialsPage> createState() => _TutorialsPageState();
}
class _TutorialsPageState extends State<TutorialsPage> {
@override
Widget build(BuildContext context) {
final pillar = PillarIhheritedWiget.of(context);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Center(
child: TutorialWidget()),
Padding(
padding: const EdgeInsets.only(top: 24.0),
child: Text(
'Total Tutorials: ${pillar.articleCount}',
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
)
],
);
}
}
lib/models/pillar.dart
import 'package:flutter/material.dart';
class Pillar extends ChangeNotifier {
var _articleCount = 0;
int get articleCount => _articleCount;
var active = true;
final PillarType type;
Pillar({required this.type, int articleCount = 10}) {
_articleCount = articleCount;
}
void increaseArticleCount({int by = 1}) {
_articleCount += by;
notifyListeners();
}
}
enum PillarType {
flutter('flutter.png', Colors.blue),
android('android.png', Colors.green),
ios('ios.png', Colors.orange);
final String imageName;
final Color backgroundColor;
const PillarType(this.imageName, this.backgroundColor);
}
lib/main.dart
import 'package:flutter/material.dart';
import 'pages/tutorials_page.dart';
import 'models/pillar.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const Application());
}
class Application extends StatefulWidget {
const Application({super.key});
@override
State<Application> createState() => _ApplicationState();
}
class _ApplicationState extends State<Application> {
final pillarData = Pillar(type: PillarType.flutter, articleCount: 115);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tutorial Tracker',
theme: ThemeData(primarySwatch: Colors.green),
home: Scaffold(
appBar: AppBar(
title: const Text('Tutorial Tracker'),
),
body: ChangeNotifierProvider<Pillar>(
create: (context) => pillarData,
child: const TutorialsPage(),
),
),
);
}
}
lib/pages/tutorials_page.dart
import 'package:flutter/material.dart';
import '../widgets/tutorial_widget.dart';
import 'package:provider/provider.dart';
import '../models/pillar.dart';
class TutorialsPage extends StatefulWidget {
const TutorialsPage({
super.key,
});
@override
State<TutorialsPage> createState() => _TutorialsPageState();
}
class _TutorialsPageState extends State<TutorialsPage> {
@override
Widget build(BuildContext context) {
final pillar = Provider.of<Pillar>(context);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Center(
child: TutorialWidget()),
Padding(
padding: const EdgeInsets.only(top: 24.0),
child: Text(
'Total Tutorials: ${pillar.articleCount}',
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
)
],
);
}
}
lib/widgets/tutorial_widget.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/pillar.dart';
class TutorialWidget extends StatefulWidget {
const TutorialWidget({
super.key,
});
@override
State<TutorialWidget> createState() => _TutorialWidgetState();
}
class _TutorialWidgetState extends State<TutorialWidget> {
@override
Widget build(BuildContext context) {
final pillar = Provider.of<Pillar>(context);
return Stack(
children: [
InkWell(
onTap: () {
pillar.increaseArticleCount();
},
child: Image.asset('assets/images/${pillar.type.imageName}',
width: 110, height: 110),
),
Positioned(
bottom: 2,
child: CircleAvatar(
backgroundColor: Colors.blue,
child: Text(pillar.articleCount.toString()),
),
)
],
);
}
}
lib/pages/tutorials_page.dart
class _TutorialsPageState extends State<TutorialsPage> {
@override
Widget build(BuildContext context) {
final pillar = context.watch<Pillar>();
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
lib/widgets/tutorial_widget.dart
class _TutorialWidgetState extends State<TutorialWidget> {
@override
Widget build(BuildContext context) {
final pillar = context.watch<Pillar>();
return Stack(
children: [
InkWell(
onTap: () {
lib/pages/tutorials_page.dart
class _TutorialsPageState extends State<TutorialsPage> {
@override
Widget build(BuildContext context) {
return Consumer<Pillar>(
builder: (_, pillar, __) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Center(child: TutorialWidget()),
Padding(
lib/widgets/tutorial_widget.dart
class _TutorialWidgetState extends State<TutorialWidget> {
@override
Widget build(BuildContext context) {
return Consumer<Pillar>(
builder: (_, pillar, __) {
return Stack(
children: [
InkWell(
onTap: () {
pillar.increaseArticleCount();
![スクリーンショット 2023-06-05 21 37 53](https://private-user-images.githubusercontent.com/47273077/243354369-fe8d67aa-d860-4caa-9ca2-93857852e37e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NTYzNjAsIm5iZiI6MTcyMTQ1NjA2MCwicGF0aCI6Ii80NzI3MzA3Ny8yNDMzNTQzNjktZmU4ZDY3YWEtZDg2MC00Y2FhLTljYTItOTM4NTc4NTJlMzdlLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzIwVDA2MTQyMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTBlMzBmM2U0ODI3ODQ4ODQwOGFmOTg2ZjRiZjI3Y2MzM2YwZDFmYmQ4ZjM3OTRkMDMwOGJhODE1MTJhNTI1NGMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.1RlethXmOfY7wxyeQ6ifdor2K27cZh4ATXguAea7Mkc)
lib/models/domain.dart
import 'package:flutter/material.dart';
import 'pillar.dart';
abstract class Domain extends ChangeNotifier {
final Pillar pillar;
Domain(this.pillar);
void increaseArticleCount({int by = 1}) {
pillar.increaseArticleCount(by: by);
notifyListeners();
}
int get articleCount => pillar.articleCount;
String get imageName => pillar.type.imageName;
Color get backgroundColor => pillar.type.backgroundColor;
}
class Flutter extends Domain {
Flutter(super.pillar);
}
class Android extends Domain {
Android(super.pillar);
}
class Swift extends Domain {
Swift(super.pillar);
}
lib/models/pillar.dart
import 'package:flutter/material.dart';
class Pillar extends ChangeNotifier {
var _articleCount = 0;
int get articleCount => _articleCount;
var active = true;
final PillarType type;
Pillar({required this.type, int articleCount = 10}) {
_articleCount = articleCount;
}
void increaseArticleCount({int by = 1}) {
_articleCount += by;
notifyListeners();
}
}
enum PillarType {
flutter('flutter.png', Colors.blue),
android('android.png', Colors.green),
ios('ios.png', Colors.orange);
final String imageName;
final Color backgroundColor;
const PillarType(this.imageName, this.backgroundColor);
}
lib/state/pillar_widget.dart
class PillarIhheritedWiget extends InheritedWidget {
final PillarState state;
final int articleCount;
const PillarIhheritedWiget(
{required this.articleCount, required this.state, super.key, required super.child});
static PillarState of(BuildContext context) {
final PillarIhheritedWiget? result =
context.dependOnInheritedWidgetOfExactType<PillarIhheritedWiget>();
assert(result != null, 'No PillarWidget found in context');
return result!.state;
}
@override
bool updateShouldNotify(PillarIhheritedWiget old) => articleCount != old.articleCount;
}
class PillarSttatefulWidget extends StatefulWidget {
final Widget child;
final Pillar pillarData;
const PillarSttatefulWidget(
{required this.pillarData, required this.child, Key? key})
: super(key: key);
@override
State<PillarSttatefulWidget> createState() => PillarState();
}
class PillarState extends State<PillarSttatefulWidget> {
get articleCount => widget.pillarData.articleCount;
get imageName => widget.pillarData.type.imageName;
void increaseArticleCount({ int by = 1}) {
setState(() {
widget.pillarData.increaseArticleCount(by: by);
});
}
@override
Widget build(BuildContext context) {
return PillarIhheritedWiget(
articleCount: articleCount,
state: this,
child: widget.child,
);
}
}
lib/pages/tutorials_page.dart
class _TutorialsPageState extends State<TutorialsPage> {
@override
Widget build(BuildContext context) {
return Consumer3<Flutter, Android, Swift>(
builder: (_, flutter, android, swift, __) {
final totalArticles =
android.articleCount + flutter.articleCount + swift.articleCount;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TutorialWidget(domain: flutter),
TutorialWidget(domain: android),
TutorialWidget(domain: swift),
],
)),