この記事ではstate管理の方法としてInheritedWidgetについて記事です。
InheritedWidgetとは下位ツリーからO(1)でアクセスできる特性を持つstate管理ウィジェットです。
まずは完成コード全体
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CartWidget(
child: MaterialApp(
title: 'Home',
home:Catalog(),
),
);
}
}
class Catalog extends StatelessWidget {
final List<Menu> catalogs = [
Menu(color: Colors.white, title: "white"),
Menu(color: Colors.black, title: "black"),
Menu(color: Colors.red, title: "red"),
Menu(color: Colors.blue, title: "blue"),
Menu(color: Colors.green, title: "green"),
Menu(color: Colors.yellow, title: "yellow"),
Menu(color: Colors.purple, title: "purple"),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Catalog"),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return Cart();
},
),
),
),
]
),
body: ListView.builder(
itemCount: catalogs.length,
itemBuilder: (BuildContext context, int index) {
final inherited =
context.inheritFromWidgetOfExactType(_Inherited)
as _Inherited;
return Container(
width: MediaQuery.of(context).size.width*0.8,
height: 100.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
color: catalogs[index].color,
border: Border.all(color: Colors.grey),
),
),
Text("${catalogs[index].title}"),
RaisedButton(
child: const Text("ADD"),
onPressed: () => inherited.state.addCart(catalogs[index])
)
]
)
);
}
),
);
}
}
class Cart extends StatelessWidget {
@override
Widget build(BuildContext context) {
final inherited = context.inheritFromWidgetOfExactType(_Inherited)
as _Inherited;
return Scaffold(
appBar: AppBar(title: Text("Cart")),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: inherited.state.cart.map((menu) => Text("${menu.title}")).toList()
)
);
}
}
class CartWidget extends StatefulWidget {
CartWidget({Key key, @required this.child}) : super(key: key);
final Widget child;
@override
_CartState createState() => _CartState();
}
class _CartState extends State<CartWidget> {
List<Menu> cart = [];
void addCart(Menu menu) {
setState(() => cart.add(menu));
}
@override
Widget build(BuildContext context) {
return _Inherited(
state: this,
child: widget.child,
);
}
}
class _Inherited extends InheritedWidget {
const _Inherited({
Key key,
@required this.state,
@required Widget child,
}) : super(key: key, child: child);
final _CartState state;
@override
bool updateShouldNotify(_Inherited old) => old.state.cart.length != state.cart.length;
}
class Menu {
final Color color;
final String title;
Menu({ @required this.color, @required this.title });
}
サンプルだけ欲しいという方は上記のコードを参照してください。
雛形の作成
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CartWidget(
child: MaterialApp(
title: 'Home',
home: Catalog(),
),
);
}
}
class Catalog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Catalog")),
body: Container(
child: Text("Catalog")
)
);
}
}
class Cart extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Cart")),
body: Container(
child: Text("Cart")
)
);
}
}
次にこの記事のメイン部分であるState管理ウィジェット
class CartWidget extends StatefulWidget {
CartWidget({Key key, @required this.child}) : super(key: key);
final Widget child;
@override
_CartState createState() => _CartState();
}
//statefulウィジェット
class _CartState extends State<CartWidget> {
List<Menu> cart = [];
void addCart(Menu menu) {
setState(() => cart.add(menu));
}
@override
Widget build(BuildContext context) {
//InheritedWidgetで囲う
return _Inherited(
state: this,
child: widget.child,
);
}
}
class _Inherited extends InheritedWidget {
const _Inherited({
Key key,
@required this.state,
@required Widget child,
}) : super(key: key, child: child);
final _CartState state;
//ウィジェットを更新する条件を記載
@override
bool updateShouldNotify(_Inherited old) => old.state.cart.length != state.cart.length;
}
カタログウィジェット
class Catalog extends StatelessWidget {
final List<Menu> catalogs = [
Menu(color: Colors.white, title: "white"),
Menu(color: Colors.black, title: "black"),
Menu(color: Colors.red, title: "red"),
Menu(color: Colors.blue, title: "blue"),
Menu(color: Colors.green, title: "green"),
Menu(color: Colors.yellow, title: "yellow"),
Menu(color: Colors.purple, title: "purple"),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Catalog"),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Shopping Cart',
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return Cart();
},
),
),
),
]
),
body: ListView.builder(
itemCount: catalogs.length,
itemBuilder: (BuildContext context, int index) {
final inherited = context.inheritFromWidgetOfExactType(_Inherited) as _Inherited;
return Container(
width: MediaQuery.of(context).size.width*0.8,
height: 100.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
color: catalogs[index].color,
border: Border.all(color: Colors.grey),
),
),
Text("${catalogs[index].title}"),
RaisedButton(
child: const Text("ADD"),
//inheritedのaddCart()を呼び出す
onPressed: () => inherited.state.addCart(catalogs[index])
)
]
)
);
}
),
);
}
}
カートウィジェット
class Cart extends StatelessWidget {
@override
Widget build(BuildContext context) {
//inheritedを取得
final inherited = context.inheritFromWidgetOfExactType(_Inherited) as _Inherited;
return Scaffold(
appBar: AppBar(title: Text("Cart")),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
//inheritedの値を取得
children: inherited.state.cart.map((menu) => Text("${menu.title}")).toList()
)
);
}
}