Open2

flutter雑記

karamawanukaramawanu

provider | Flutter Package

flutterのprividerはカウンターのサンプルしかないので他の構造の時のやりかたが全然頭に入ってこない。のだが、試行錯誤の末にようやくわかった。

  • 画面を横断するデータはclass T extends ChangeNotifier する必要がある。※ここではそういうことにする
  • データの入れ方は、アプリ実装者の都合で構わない。StatelessWidget::build()が呼ばれたときに帳尻があえば良い
  • MatrialApp の直下あたりで ChangeNotifierProvider<T>(create:T) で括り付ける。※ここではそういうことにする
  • 以降、StatelessWidgetで作る。
  • 画面更新では、StatefulWidget/Stateとは別の機構をつかうため、
  • Provider.of<T>(BuilderContext) で、上でくくりつけたデータを取り出す。
  • Consumer<T>()の説明をしてる例が非常に多いが、慣れないうちは無名関数の段が増えて判りにくくなるので、Provider.ofを会得してから移行していけばええんやで。
  • of<T>の時点でlistnerの登録が行われている。
  • 画面更新に直接関係ないデータ参照は Provider.of<T>(context, listen: false) を付ける(文字通り listener非対象となる )
  • データ更新は、T の中身を更新したのち、T::notifyListeners() を呼ぶ
  • のだがこれはprotectedなので、たいていのサンプルでは、setterで同時に実施する。
  • なれないうちは notify() => notifyListers() から呼んでもええんやで※ここではそういうことにする
  • Provider.of<T>(listen:true)の参照をしてるところに更新がかかる
  • 前述の通りBuilderContext 経由で T が取り出せるので、画面を横断してデータを共通化できるという筋書き。
  • 複数系統の更新タイミングがある場合、別のTを用意して使い分ける。
karamawanukaramawanu

以前習作で造っただけで、大変なことになったので、もうちょっと何とかなりませんかねという話。

全部網羅する気はありません。

局所的

Widgetに対して適切な拡張メソッドを造っておき、メソッドチェインで構築する。

Dart extensions to flatten Flutter's deep nested widget trees

extension WidgetModifier on Widget {

   Widget cornerRadius(BorderRadiusGeometry radius) {
    return ClipRRect(
      borderRadius: radius,
      child: this,
    );
  }

こういうを色々造っておけば

  
  Widget build(BuildContext context) {
    return Text('Hello, World!', style: Theme.of(context).textTheme.headline4)
            .padding()
            .background(Colors.lightBlue)
            .cornerRadius(BorderRadius.all(Radius.circular(8.0)))
            .padding(EdgeInsets.symmetric(horizontal: 8, vertical: 16))
            .background(Colors.purple);
  }

こう出来るよねと。

ソースはかなり素敵に観えるが、内部で結局 child:this してるのでソースの絵面と親子関係が逆転する。拡張メソッドの設計にセンスと知見が要りそう。

全体的

How to do nested navigation in Flutter - Stack Overflow

なんとなくしか理解できてない

final _libraryScreen = GlobalKey<NavigatorState>();

       children: <Widget>[
          Navigator(
            key: _libraryScreen,
            onGenerateRoute: (route) => MaterialPageRoute(
              settings: route,
              builder: (context) => LibraryScreen(),
            ),
          ),

としておいて

  void _onTap(int val, BuildContext context) {
    if (_currentIndex == val) {
      switch (val) {
        case 0:
          _libraryScreen.currentState.popUntil((route) => route.isFirst);
          break;

こうする