我有一个DefaultTabController,我有一个方法,返回List<PreferredSizeWidget>,这是AppBar的页面。我想让它们在ChangeNotifier中观察一个状态,因此我想把它们 Package 在Consumer中。当我尝试这样做时,我会得到这样的错误:“无法将参数类型”Widget“分配给参数类型”WebRedSizeWidget“。”我该怎么办?谢谢和问候。
DefaultTabController
List<PreferredSizeWidget>
AppBar
ChangeNotifier
Consumer
lymnna711#
错误来自appBar的Scaffold参数需要一个PreferredSizeWidget。我能想到两个解决办法:
appBar
Scaffold
PreferredSizeWidget
PreferredSize
Size.fromHeight()
preferredSize
Column
Expanded
rhfm7lfc2#
这是我基于Mickael建议的实现:首先,我添加了一个AppBarParams类来保存AppBar状态
AppBarParams
@freezed class AppBarParams with _$AppBarParams { const factory AppBarParams({ required String title, required List<Widget> actions, }) = _AppBarParams; }
然后我在全局提供程序文件中创建了一个StateProvider,如下所示:
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 } }
t30tvxxf3#
我建议再次将整个AppBar Package 在Consumer中。你应该 Package 内appbar领域的小部件(如领导,标题等)与消费者。在Flutter的文档中提到它是为了将消费者保持在尽可能低的水平。如果你想让它们有条件地出现,你可以按照下面的做法:
AppBar(actions:[ Consumer<Provider>(builder: (context,value,child) => value.toShow() ? MyWidget() : const SizedBox() ) ] );
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
4条答案
按热度按时间lymnna711#
错误来自
appBar
的Scaffold
参数需要一个PreferredSizeWidget
。我能想到两个解决办法:Consumer
Package 为PreferredSize
,并将Size.fromHeight()
用作preferredSize
。也就是说,如果高度在应用栏中是恒定的。appBar
参数,方法是在Column
中使用Expanded
PackageScaffold
的主体,并将Consumer
作为其第一个子对象。rhfm7lfc2#
这是我基于Mickael建议的实现:
首先,我添加了一个
AppBarParams
类来保存AppBar状态然后我在全局提供程序文件中创建了一个
StateProvider
,如下所示:并在主应用程序中附加了一个
Consumer
:然后你只需要编辑provider状态来相应地更新AppBar,当用户在页面之间切换时更新AppBar,我已经创建了这个mixin:
而在每一个主屏幕视图,其中必须改变标题或行动,我这样做:
t30tvxxf3#
我建议再次将整个AppBar Package 在Consumer中。你应该 Package 内appbar领域的小部件(如领导,标题等)与消费者。在Flutter的文档中提到它是为了将消费者保持在尽可能低的水平。如果你想让它们有条件地出现,你可以按照下面的做法:
um6iljoc4#
我建议使用以下模式:
然后这样使用:
解决方案的关键是:
类MyRiverPodAppBar扩展ConsumerWidget实现了UsredSizeWidget