dart Riverpod -如何在消费者中 Package 一个WebRedSizeWidget

sauutmhj  于 2023-10-13  发布在  其他
关注(0)|答案(4)|浏览(107)

我有一个DefaultTabController,我有一个方法,返回List<PreferredSizeWidget>,这是AppBar的页面。我想让它们在ChangeNotifier中观察一个状态,因此我想把它们 Package 在Consumer中。当我尝试这样做时,我会得到这样的错误:
“无法将参数类型”Widget“分配给参数类型”WebRedSizeWidget“。”
我该怎么办?
谢谢和问候。

lymnna71

lymnna711#

错误来自appBarScaffold参数需要一个PreferredSizeWidget。我能想到两个解决办法:

  • 您可以将Consumer Package 为PreferredSize,并将Size.fromHeight()用作preferredSize。也就是说,如果高度在应用栏中是恒定的。
  • 您可以完全避免使用appBar参数,方法是在Column中使用Expanded Package Scaffold的主体,并将Consumer作为其第一个子对象。
rhfm7lfc

rhfm7lfc2#

这是我基于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
        )
      )
    )
  }
}

然后你只需要编辑provider状态来相应地更新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
  }
}
t30tvxxf

t30tvxxf3#

我建议再次将整个AppBar Package 在Consumer中。你应该 Package 内appbar领域的小部件(如领导,标题等)与消费者。在Flutter的文档中提到它是为了将消费者保持在尽可能低的水平。如果你想让它们有条件地出现,你可以按照下面的做法:

AppBar(actions:[
    Consumer<Provider>(builder: (context,value,child) => value.toShow() ? 
         MyWidget() : const SizedBox()
                       )
                ]
       );
um6iljoc

um6iljoc4#

我建议使用以下模式:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final helloWorldProvider = Provider<String>((ref) {
  return 'Hello world';
});

class MyRiverPodAppBar extends ConsumerWidget implements PreferredSizeWidget {
  const MyRiverPodAppBar({
    super.key,
  });

  @override
  // kToolbarHeight is the default, you can implement an argument to pass in your variable height
  Size get preferredSize => const Size.fromHeight(kToolbarHeight);

  @override
  PreferredSizeWidget build(BuildContext context, WidgetRef ref) {
    String myProvidedString = ref.watch(helloWorldProvider);
    return AppBar(title: Text(myProvidedString), titleSpacing: 0, actions: <Widget>[
      IconButton(
        icon: const Icon(Icons.image),
        tooltip: 'Just a demo',
        enableFeedback: true,
        onPressed: () {
          print('Do whatever you want');
        },
        padding: const EdgeInsets.symmetric(horizontal: -2.0),
        visualDensity: const VisualDensity(
          horizontal: -4.0,
        ),
      ),
    ]);
  }
}

然后这样使用:

return Scaffold(
  appBar: MyRiverPodAppBar (),

解决方案的关键是:

类MyRiverPodAppBar扩展ConsumerWidget实现了UsredSizeWidget

相关问题