1

我正在尝试使以下工作。应用程序模型状态的更改不会通过 InheritedWidget 'AppStateProvider' 获取。我已经设法让它与接收器/流一起工作,但希望建立一个更简单的结构。

这只是一个在各种应用模式之间切换的测试应用。

少了什么东西?

import 'package:flutter/material.dart';

void main() {
  runApp(AppStateProvider(
    child: RootPage(),
    appState: new AppState(),
  ));
}

enum AppMode { introduction, login, home }

class AppState {
  AppMode appMode;
  AppState({
    this.appMode = AppMode.introduction,
  });
}

class AppStateProvider extends InheritedWidget {
  final AppState appState;

  AppStateProvider({Key key, Widget child, this.appState})
      : super(key: key, child: child);

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) => true;

  static AppStateProvider of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(AppStateProvider)
        as AppStateProvider);
  }
}

class RootPage extends StatelessWidget {
  AppMode _mode;

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Inherited Widget Test',
      theme: new ThemeData(
        primarySwatch: Colors.blueGrey,
      ),
      home: _body(context),
    );
  }

  Widget _body(BuildContext context) {
    final provider = AppStateProvider.of(context); //Registers as a listener
    final state = provider.appState;
    _mode = state.appMode;

    return new Stack(
      children: <Widget>[
        new Offstage(
          offstage: _mode != AppMode.introduction,
          child: new MaterialApp(
            home: ColorsListPage(
              color: Colors.red,
              targetAppMode: AppMode.login,
              title: "Intro",
            ),
          ),
        ),
        new Offstage(
          offstage: _mode != AppMode.login,
          child: new MaterialApp(
            home: ColorsListPage(
              color: Colors.blue,
              targetAppMode: AppMode.home,
              title: "Login",
            ),
          ),
        ),
        new Offstage(
          offstage: _mode != AppMode.home,
          child: new MaterialApp(
            home: ColorsListPage(
              color: Colors.green,
              targetAppMode: AppMode.introduction,
              title: "Home",
            ),
          ),
        ),
      ],
    );
  }
}

class ColorDetailPage extends StatefulWidget {
  final String title;
  final MaterialColor color;
  final int materialIndex;
  final AppMode targetAppMode;

  ColorDetailPage(
      {this.color, this.title, this.targetAppMode, this.materialIndex: 500});

  @override
  _ColorDetailPageState createState() => new _ColorDetailPageState();
}

class _ColorDetailPageState extends State<ColorDetailPage> {
  @override
  Widget build(BuildContext context) {
    final provider = AppStateProvider.of(context);

    return Scaffold(
      appBar: AppBar(
        backgroundColor: widget.color,
        title: Text(
          '$widget.title[$widget.materialIndex]',
        ),
      ),
      body: Container(
        color: widget.color[widget.materialIndex],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            provider.appState.appMode = widget.targetAppMode;
          });
        },
        heroTag: null,
      ),
    );
  }
}

class ColorsListPage extends StatefulWidget {
  final MaterialColor color;
  final String title;
  final ValueChanged<int> onPush;
  final AppMode targetAppMode;
  final List<int> materialIndices = [
    100,
    200,
    300,
    400,
    500,
    600,
    700,
    800,
    900,
  ];

  ColorsListPage({this.color, this.targetAppMode, this.title, this.onPush});

  @override
  _ColorsListPageState createState() => new _ColorsListPageState();
}

class _ColorsListPageState extends State<ColorsListPage> {
  @override
  Widget build(BuildContext context) {
    final provider = AppStateProvider.of(context);

    return new Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
          backgroundColor: widget.color,
        ),
        body: Container(
          color: Colors.white,
          child: _buildList(context),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              provider.appState.appMode = widget.targetAppMode;
            });
          },
          heroTag: null,
        ));
  }

  Widget _buildList(BuildContext context) {
    return ListView.builder(
      itemCount: widget.materialIndices.length,
      itemBuilder: (BuildContext content, int index) {
        int materialIndex = widget.materialIndices[index];
        return Container(
            color: widget.color[materialIndex],
            child: ListTile(
                title: Text(
                  "$materialIndex",
                  style: TextStyle(fontSize: 24.0),
                ),
                trailing: Icon(Icons.chevron_right),
                onTap: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => ColorDetailPage(
                              color: widget.color,
                              title: widget.title,
                              targetAppMode: widget.targetAppMode,
                              materialIndex: materialIndex,
                            )),
                  );
                }
                //onTap: () => onPush(materialIndex),
                ));
      },
    );
  }
}
4

1 回答 1

2

你需要把你的InheritedWidget内部包裹起来StatefulWidget

class _AppStateProvider extends InheritedWidget {
  final AppStateProviderState data;

  _AppStateProvider({Key key, @required Widget child, @required this.data})
      : super(key: key, child: child);

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) => true;
}

class AppStateProvider extends StatefulWidget {
  final Widget child;
  final AppState appState;

  AppStateProvider({
    @required this.child,
    @required this.appState,
  });

  static AppStateProviderState of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(_AppStateProvider)
            as _AppStateProvider)
        .data;
  }

  @override
  AppStateProviderState createState() => AppStateProviderState(
        appState,
      );
}

class AppStateProviderState extends State<AppStateProvider> {
  AppState appState;

  AppStateProviderState(this.appState);

  void updateAppMode(AppMode appMode) {
    setState(() {
      appState.appMode = appMode;
    });
  }

  @override
  Widget build(BuildContext context) {
    return _AppStateProvider(
      data: this,
      child: widget.child,
    );
  }
}

了解更多信息

注意这个方法:

  void updateAppMode(AppMode appMode) {
    setState(() {
      appState.appMode = appMode;
    });
  }

你可以像这样使用它:

  floatingActionButton: FloatingActionButton(
    onPressed: () {
      provider.updateAppMode(widget.targetAppMode);
    },
    heroTag: null,
  ),

在此处输入图像描述

于 2018-07-18T09:57:36.817 回答