我创建了一个 Flutter 页面,其中有一堆输入。我认为这是一团糟,让我们重构它并为每个输入创建一个新的有状态小部件。
这很好,除了数据需要在父小部件中,而且我很难理解如何将数据从新的子小部件传递回父小部件。
我发现了一些方法,你传入一个函数,只要有变化,你就通过该函数将数据传递给父级。
我已经阅读了有关集团模式的内容,但我不确定这是否是我所需要的。我只想要一个单例样式对象,当有新输入时,主小部件及其子部件都可以读取并更新子部件。
有人能解释一下 bloc 模式是否会帮助我解决这个问题,或者是否有另一种设计模式可以帮助我解决这个问题。
** 编辑
谢谢你们的好答案。我的新问题与提供者模式/库有关。
我创建了一些状态类如下(我替换了内容以尝试保持简单)
class State1 with ChangeNotifier{
String _s;
set s(String newS){
_s = newS;
notifyListeners();
}
}
Run Code Online (Sandbox Code Playgroud)
然后我使用 multiprovider 来传递它(在 init 中创建对象)
child: MultiProvider(
providers: [
ChangeNotifierProvider(builder: (context) => state1),
],
child: Stack(
alignment: Alignment.center,
children: stackChildren,
),
Run Code Online (Sandbox Code Playgroud)
然后使用子项widegets构建方法访问
state1Var = Provider.of<State1>(context);
Run Code Online (Sandbox Code Playgroud)
所有这些都很好用..
我的问题是当我开始使用导航推送时,我无法再访问状态。
onPressed: (() {
Navigator.push(
contextField,
MaterialPageRoute(builder: (context) => NewPage()),
);
}),
Run Code Online (Sandbox Code Playgroud)
当我收到此错误时
Could not find the correct Provider<State1> above this NewPage Widget...
Run Code Online (Sandbox Code Playgroud)
我确实设法使用它获得了它
Navigator.push(
context, …Run Code Online (Sandbox Code Playgroud) 我的目标是创建一个应用程序,用户可以在其中选择他喜欢的主题。我使用共享首选项保存用户的选择,以便我可以在下次应用程序启动时加载它。用户可以选择: - 深色模式(独立于操作系统设置) - 浅色模式(独立于操作系统设置) - 系统(根据操作系统设置在深色模式和浅色模式之间进行更改) 在 BLoC 的帮助下,我几乎达到了我想要的。但问题是我需要在 Bloc 事件中传递亮度。为了获得系统(操作系统)亮度,我需要利用
MediaQuery.of(context).platformBrightness
Run Code Online (Sandbox Code Playgroud)
但 Bloc 在 MaterialApp 之前启动,因此 MediaQuery 不可用。当然,我可以稍后传递亮度(从 MaterialApp 的子小部件),但随后(例如,如果用户激活了黑暗模式)它会从亮到暗,但对用户来说可见的时间很短(因为在 InitialState 内)我在灯光模式下通过了)。
class MyApp extends StatelessWidget {
final RecipeRepository recipeRepository;
MyApp({Key key, @required this.recipeRepository})
: assert(recipeRepository != null),
super(key: key);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<ThemeBloc>(create: (context) =>
ThemeBloc(),),
],
child: BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state){
return MaterialApp(
theme: state.themeData,
title: 'Flutter Weather',
localizationsDelegates: [
FlutterI18nDelegate(fallbackFile: 'en',),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
supportedLocales: [
const Locale("en"), …Run Code Online (Sandbox Code Playgroud) //File: email_sign_in_model.dart
class EmailSignInModel {
EmailSignInModel({
this.email='',
this.formType=EmailSignInFormType.signIn,
this.isLoading=false,
this.password='',
this.submitted=false,
});
final String email;
final String password;
final EmailSignInFormType formType;
final bool isLoading;
final bool submitted;
EmailSignInModel copyWith({
String email,
String password,
EmailSignInFormType formType,
bool isLoading,
bool submitted,
}) {
return EmailSignInModel(
email: email ?? this.email,
password: password?? this.password,
formType: formType?? this.formType,
isLoading: isLoading?? this.isLoading,
submitted: submitted?? this.submitted
);
}
}
//File: email_sign_in_bloc.dart
import 'dart:async';
import 'package:timetrackerapp/app/sign_in/email_sign_in_model.dart';
class EmailSignInBloc {
final StreamController<EmailSignInModel> _modelController = StreamController<EmailSignInModel>();
Stream<EmailSignInModel> get modelStream => …Run Code Online (Sandbox Code Playgroud) 在我的 flutter 应用程序中,我使用flutter_bloc进行状态管理。
有bloc问题的使用repository. 订阅repositorywebsocket,并将新数据添加到流中。
问题:我的块监听流:
InvestmentClubBloc({
required this.investmentClubRepository
}) : super(InvestmentClubLoading()) {
onChangeSubscription = investmentClubRepository.onNewMessage.listen(
(event) {
emit(NewMessageState(event); // <-- The member "emit" can only be used within 'package:bloc/src/bloc.dart' or in test
},
);
}
Run Code Online (Sandbox Code Playgroud)
问题是emit不起作用(我收到警告“成员“emit”只能在 'package:bloc/src/bloc.dart' 或测试中使用”)
bloc 如何监听流并根据流事件发出新状态?
我对 Flutter 和 BLoC 模式比较陌生,所以我仍然试图把我的头脑围绕在所有事情上。
假设我有一个测验应用程序,其中有一个名为 BLoC 的应用程序,QuestionBloc它使用存储库从文件中获取问题。事件发生QuestionBloc
FetchQuestion状态 QuestionBloc
QuestionEmptyQuestionLoadingQuestionLoaded 其中包含一个问题对象QuestionError然后我调用了另一个 BLoC QuestionValidatorBloc,它负责验证问题的答案。答案被输入到一个文本字段中,并且有一个提交按钮来触发验证。事件发生QuestionValidatorBloc
ValidateQuestion状态 QuestionValidatorBloc
ValidateInitialValidateInProgressValidateSuccessValidateError这是相当直接的。不过,现在我需要二者结合QuestionBloc并QuestionValidatorBloc在同一个部件,因为其中一人负责获取和显示问题和其他处理验证动作。我怎样才能做到这一点?
Widget build(BuildContext context) {
final appBar = AppBar(
title: Text(
"Romantic Comedy",
),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(
context: context,
delegate: MaterialSearch(_pagingController.itemList));
},
),
],
);
return Scaffold(
backgroundColor: Colors.black,
appBar: appBar,
body: BlocConsumer<MovieBloc, MovieState>(
listener: (context, movieState) {
},
builder: (context, movieState) {
if (movieState is MovieSuccessState) {
movieBloc.movies.addAll(movieState.movies);
}
return GridView.builder(
controller: _scrollController
..addListener(() {
if (_scrollController.offset ==
_scrollController.position.maxScrollExtent) {
context.bloc<MovieBloc>()
..isFetching = true
..add(Fetch());
}
}),
padding: EdgeInsets.only(left: 12.0, right: 12.0),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( …Run Code Online (Sandbox Code Playgroud) 我正在 Flutter 中开发一个多语言应用程序。
我使用flutter_localizations包进行本地化,使用 intl包进行国际化。
以 Widgets 内的正常方式,我可以在Context的帮助下使用它。
但问题是当我想在存储库或除 UI 层之外的其他层中使用国际化时。
除了 UI(我们无法访问Context)之外的其他层中进行国际化的最佳实践是什么,例如在 Api、Repository、Bloc 或 Cubit 中使用国际化?
注意:我正在寻找一种在应用程序的 BLOC(业务逻辑)内部使用国际化的方法,而不是 UI!
在登录视图中,如果用户在没有插入凭据的情况下点击登录按钮,则 LoginFailState 为 yield 并且视图对其做出反应。如果他再次点击,这个 LoginFailstate 又是 yield ,但视图不会对它做出反应。那么,有没有办法在相同的状态下产生更多倍的结果?
有一些代码可以更好地解释我的情况:
class LoginBloc extends Bloc<LoginEvent, LoginState> {
@override
LoginState get initialState => LoginUninitialized();
@override
Stream<LoginState> mapEventToState(LoginEvent event) {
if (event is loginButtonPressed) {
yield LoginFailState();
}
}
Run Code Online (Sandbox Code Playgroud)
看法:
@override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: _loginBloc,
builder: (BuildContext context, LoginState state) {
if (state is LoginFail) {
print ('Login fail');
}
return Column(
...
)
Run Code Online (Sandbox Code Playgroud) 我遵循 BLoC 模式并订阅流,并对构建方法中的状态变化做出反应。加载数据后,我想关闭屏幕。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bloc'),
),
body: SafeArea(
child: StreamBuilder<UserState>(
stream: _userBloc.user,
initialData: UserInitState(),
builder: (context, snapshot) {
if (snapshot.data is UserInitState) {
return _buildInit();
}
if (snapshot.data is UserDataState) {
Navigator.pop(context, true);
return Container();
}
if (snapshot.data is UserLoadingState) {
return _buildLoading();
}
},
),
),
);
}
Run Code Online (Sandbox Code Playgroud)
当我Navigator.pop(context, true);使用build()方法时,我得到:
I/flutter ( 4360): ??? EXCEPTION CAUGHT BY ANIMATION LIBRARY ??????????????????????????????????????????????????????????
I/flutter ( 4360): The following …Run Code Online (Sandbox Code Playgroud) 所以我通读Bloc了状态管理flutter。
由于 Bloc 允许您下沉和流式传输(根据输入重建小部件),那么是否有可能主要使用无状态小部件来构建应用程序?
例如,假设我制作了许多单个无状态类小部件,因此几乎所有东西都被划分为自己的无状态小部件。
使用 Bloc 状态管理,我可以简单地重建某个无状态的子小部件来反映更改。
在这种方法中,我认为不需要使用有状态小部件。当然,作为一个完全的初学者flutter,我想听听这种方法是否有任何优点。
这是一个好方法吗?任何信息将不胜感激。
bloc ×10
flutter ×10
dart ×5
flutter-bloc ×3
cubit ×1
forms ×1
handle ×1
ios-darkmode ×1
localization ×1
state ×1
stateless ×1
stream ×1