当您无法访问脚手架时,如何在应用栏中交换/删除操作?

Posted

技术标签:

【中文标题】当您无法访问脚手架时,如何在应用栏中交换/删除操作?【英文标题】:How do you swap/remove actions in the app bar in flutter when you have no access to the scaffold? 【发布时间】:2020-05-23 17:15:06 【问题描述】:

我的情况如下:

我有一个带有 appbar 和标签栏的脚手架,在脚手架的主体中,我的 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(),
          ],
        ),
      ),
    );
  

现在每个小部件都必须定义自己的操作以添加到应用栏,您如何习惯性地将正确的操作设置到父脚手架?我已经尝试创建一个自定义 tabController 并监听事件,并在运行时交换按钮,但它似乎赋予标签控制器对其子行为和内部逻辑的责任。 有没有办法从子小部件(在示例中我指的是FirstWidgetSecondWidget)中查询脚手架并将操作设置到应用栏(最终结束浮动操作按钮)。

我正在寻找类似Scaffold.of(context).setAppBarActions(...) 的东西。 我发现this question 非常相似,但是我不同意该解决方案,因为它要求父脚手架具有知识(并生成)具有与其子级相关的行为的小部件,我想避免它。

【问题讨论】:

【参考方案1】:

您可以使用包提供程序来获得像Scaffold.of(context).setAppBarActions(...) 这样的功能。

使用child 很重要,以避免每次您希望AppBar 重建时都重建TabBarView

FirstWidgetSecondWidget 中访问context 很痛苦,因为contextinitState 中不可用,因此必须使用后帧回调。

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)"));
  

【讨论】:

setAppBarActions() 不存在 @chitgoks 这正是我回答这个问题的原因。 是的,没错。这很奇怪。必须安装提供程序只是为了公开来自不同类的方法

以上是关于当您无法访问脚手架时,如何在应用栏中交换/删除操作?的主要内容,如果未能解决你的问题,请参考以下文章

无法删除 sliver 应用栏中的后退按钮

Rails 脚手架黑色背景

Flutter:如何将可访问性焦点集中到自定义应用栏

未在颤振自定义应用程序栏中获取脚手架上下文

如何隐藏或删除Apple Watch状态栏中的时间?

Nativescript - 搜索栏在操作栏中无法正确显示(IOS)