2

我有一个DefaultTabController并且我有一个返回页面List<PreferredSizeWidget>的方法AppBar。我希望他们在 a 中观看状态,ChangeNotifier因此我想将它们包装在 a 中Consumer。当我尝试这样做时,我收到如下错误:

“参数类型‘Widget’不能分配给参数类型‘PreferredSizeWidget’。”

我怎样才能解决这个问题?

谢谢并恭祝安康。

4

3 回答 3

5

错误来自要求 a的appBar's 参数。我可以想到两种解决方案:ScaffoldPreferredSizeWidget

  • 你可以用 a 包装你ConsumerPreferredSize并使用Size.fromHeight()as preferredSize。也就是说,如果您的应用栏之间的高度是恒定的。
  • 您可以通过用内部 aappBar包裹您Scaffold的主体并使其成为第一个孩子来完全避免使用该参数。ExpandedColumnConsumer
于 2020-12-13T20:42:26.827 回答
1

这是我基于 Mickael 建议的实现:

首先,我创建了一个AppBarParams类来保存 AppBar 状态

@freezed
class AppBarParams with _$AppBarParams {
  const factory AppBarParams({
    required String title,
    required List<Widget> actions,
  }) = _AppBarParams;
}

然后我创建了一个StateProvider全局提供程序文件,如下所示:

final appBarParamsProvider = StateProvider<AppBarParams>((ref) {
  return AppBarParams(title: "Default title", actions: []);
});

并将其附加到主应用程序中Consumer

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: "App Title",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SafeArea(
        child: Scaffold(
          appBar: PreferredSize(
            preferredSize: Size.fromHeight(kToolbarHeight),
            child: Consumer(
              builder: (context, watch, child) {
                final appBarParams = watch(appBarParamsProvider).state;
                return AppBar(
                  title: Text(appBarParams.title),
                  actions: appBarParams.actions
                );
            })
          ),
          body: ... your body widget
        )
      )
    )
  }
}

然后你只需要编辑提供者状态来相应地更新 AppBar,当用户在页面之间切换时更新 AppBar,我创建了这个 mixin:

mixin AppBarHandler {

  void updateAppBarParams(
    BuildContext context, {
    required String title,
    List<Widget> Function()? actions
  }) {
    WidgetsBinding.instance!.addPostFrameCallback((_) async {
      context.read(appBarParamsProvider).state = context
        .read(appBarParamsProvider).state
        .copyWith(
           title: title, 
           actions: actions != null ? actions() : []
        );
    });
  }
}

在每个必须更改标题或操作的主屏幕视图中,我都这样做了:

class Page1 extends HookWidget with AppBarHandler {

  const Page1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    updateAppBarParams(context, 
      title: "Page 1 title",
      actions: () => [
        IconButton(icon: const Icon(Icons.refresh), onPressed: () {
          //a custom action for Page1
          context.read(provider.notifier).updateEntries();
        })
      ]
    );
    ... your screen widget
  }
}
于 2021-04-11T17:10:34.487 回答
0

我建议再次将整个 AppBar 包装在 Consumer 中。您应该使用消费者将小部件包装在 appbar 字段(如前导、标题等)中。Flutter 的文档中提到了将 Consumer 保持在尽可能低的级别。如果您希望它们有条件地出现,您可以遵循以下做法:

AppBar(actions:[
    Consumer<Provider>(builder: (context,value,child) => value.toShow() ? 
         MyWidget() : const SizedBox()
                       )
                ]
       );
于 2022-01-18T19:10:49.643 回答