我处于以下情况:

我有一个带有应用栏和选项卡栏的支架,在支架的主体中,我的TabBarView带有两个有状态的小部件作为选项卡,如下所示

 @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            tabs: [
              Tab(text: "First"),
              Tab(text: "Second"),
            ],
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            FirstWidget(),
            SecondWidget(),
          ],
        ),
      ),
    );
  }

现在,每个小部件都必须定义要添加到应用程序栏中的自己的 Action ,您如何习惯地将正确的 Action 设置给父支架?我尝试过创建一个自定义的tabController并侦听事件,并在运行时交换按钮,但是似乎在其子行为和内部逻辑上赋予了Tab Controller 以责任。
有没有一种方法可以查询支架并将操作设置为子控件内的应用程序栏(最终结束为 float actionButton)(在示例中,我指的是FirstWidgetSecondWidget)。

我一直在寻找Scaffold.of(context).setAppBarActions(...)这样的东西。
我发现this question非常相似,但是我不同意该解决方案,因为它需要父脚手架具有与行为有关的知识(并生成)小部件,并且我希望避免这种情况。

最佳答案

您可以使用包提供程序来获取诸如Scaffold.of(context).setAppBarActions(...)之类的功能。

使用child对于避免每次您想要重建TabBarView时都避免重建AppBar很重要。

由于context中没有FirstWidget,因此无法访问SecondWidgetcontext中的initState,因此必须使用后框架回调。

import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

Future<void> main() async {
  return runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return MaterialApp(
      title: 'My App',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: MyHomePage(),
    );
  }
}

class ActionWidgets with ChangeNotifier {
  List<Widget> _widgets = <Widget>[];

  UnmodifiableListView<Widget> get widgets {
    return UnmodifiableListView<Widget>(this._widgets);
  }

  set widgets(final List<Widget> widgets) {
    this._widgets = widgets;
    this.notifyListeners();
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: MultiProvider(
        providers: [
          ChangeNotifierProvider<ActionWidgets>(
            create: (final BuildContext buildContext) {
              return ActionWidgets();
            },
          ),
        ],
        child: Consumer<ActionWidgets>(
          builder: (final BuildContext context, final ActionWidgets actionWidgets, final Widget child) {
            return Scaffold(
              appBar: AppBar(
                title: const Text("My Home Page"),
                actions: actionWidgets.widgets,
                bottom: TabBar(
                  tabs: [
                    Tab(text: "First (comm)"),
                    Tab(text: "Second (social)"),
                  ],
                ),
              ),
              body: child,
            );
          },
          child: TabBarView(
            children: <Widget>[
              FirstWidget(),
              SecondWidget(),
            ],
          ),
        ),
      ),
    );
  }
}

class FirstWidget extends StatefulWidget {
  @override
  _FirstWidgetState createState() {
    return _FirstWidgetState();
  }
}

class _FirstWidgetState extends State<FirstWidget> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((final Duration _) {
      final ActionWidgets actionWidgets = Provider.of<ActionWidgets>(this.context, listen: false);
      actionWidgets.widgets = <Widget>[
        Icon(Icons.email),
        Icon(Icons.phone),
      ];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(child: Text("First Widget (communication)"));
  }
}

class SecondWidget extends StatefulWidget {
  @override
  _SecondWidgetState createState() {
    return _SecondWidgetState();
  }
}

class _SecondWidgetState extends State<SecondWidget> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((final Duration _) {
      final ActionWidgets actionWidgets = Provider.of<ActionWidgets>(this.context, listen: false);
      actionWidgets.widgets = <Widget>[
        Icon(Icons.group),
        Icon(Icons.person_add),
      ];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Second Widget (social)"));
  }
}

10-08 16:34