0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Flutterのstate管理を理解する【InheritedWidget編】

Last updated at Posted at 2020-05-24

この記事ではstate管理の方法としてInheritedWidgetについて記事です。
InheritedWidgetとは下位ツリーからO(1)でアクセスできる特性を持つstate管理ウィジェットです。

今回はシンプルなショッピングアプリを用いて学習する。
スクリーンショット 2020-05-24 12.32.57.png

まずは完成コード全体

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()
      )
    );
  }
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?