Я использую BLoC. Как его правильно создать, что бы не возникало из-за отсутствия виджетов вниз по дереву виджетов. Теперь мне обычно нравится это:
Widget build(BuildContext context) {
return MaterialApp(
// debugShowCheckedModeBanner: false,
theme: Styles.appTheme,
home: BlocProvider<TokenBloc>(
create: (context) => di.sl<TokenBloc>(),
child: _childTokenBloc,
),
);
}
Widget get _childTokenBloc {
return BlocBuilder<TokenBloc, TokenState>(builder: (context, state) {
if (state is TokenInitialState) {
context.read<TokenBloc>().add(TokenCheckEvent());
return const LogoImage();
}
if (state is TokenCheckState) {
return const LogoImage();
}
if (state is TokenOkState) {
return MainPageWidget();
}
if (state is TokenNoAuthorizationState) {
return const AuthorizationPageWidget();
}
return const LogoImage();
}
);
}
В AuthorizationPageWidget я делаю:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ConfirmAuthorizationPage()),
);
А из ConfirmAuthorizationPage пытаюсь обратиться к TokenBloc:
context.read<TokenBloc>().add(TokenAddEvent());
но получаю ошибку: Не удалось найти нужного провайдера над этим виджетом приложения.
Я думал, что TokenBloc будет найден в дереве виджетов, но не так ли? И как исправить эту проблему? Нужно использовать MultiBlocProvider в методе сборки виджета ConfirmAuthorizationPage? Он будет повторно инициализирован, а предыдущий использоваться не будет.
Обновление 1: Код AuthorizationPageWidget:
class AuthorizationPageWidget extends StatefulWidget {
const AuthorizationPageWidget({Key? key}) : super(key: key);
@override
_AuthorizationPageWidgetState createState() =>
_AuthorizationPageWidgetState();
}
class _AuthorizationPageWidgetState extends State<AuthorizationPageWidget> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider<AuthorizationBloc>(
create: (context) => sl<AuthorizationBloc>(),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_title,
_description,
Expanded(child: Align(alignment: FractionalOffset.bottomCenter, child: _bottomButton))
],
),
),
),
);
}
//......
void pushConfirmPage(String number) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ConfirmAuthorizationPage(number: number,)),
);
}
}





Если вы хотите предоставить свой блок во всех своих приложениях, вы должны написать его в своем MaterialApp вот так, а не в теле;
return
BlocProvider<TokenBloc>( // like this
create: (context) => TokenBloc(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: _TokenHome(),
),
),
);
class _TokenHome extends StatelessWidget { // use a class instead of function
const _TokenHome({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<TokenBloc, TokenState>(
builder: (context, state) {
if (state is TokenInitialState) {
context.read<TokenBloc>().add(TokenCheckEvent());
return const LogoImage();
}
if (state is TokenCheckState) {
return const LogoImage();
}
if (state is TokenOkState) {
return MainPageWidget();
}
if (state is TokenNoAuthorizationState) {
return const AuthorizationPageWidget();
}
return Container(
width: 50,
height: 50,
color: Colors.red,
); // use this if there is not a state
}
);
}
}
Если по какой-то причине он больше ничего не показывает, то это потому, что некоторые из ваших классов, таких как AuthorizationPageWidget или LogoImage, неверны, проверьте это.
-------- РЕДАКТИРОВАТЬ
Использование БлокПровайдер на каждой странице может быть полезным, но имейте в виду, что, например, АвторизацияБлок будет работать только для своих дочерних элементов, если вы вызовете его на другой стороне экрана, он не будет работать, поэтому настоятельно рекомендуется использовать MultiBlocProvider в Материал Приложение. избежать проблем в будущем;
return MultiBlocProvider( // like this
providers: [
BlocProvider<TokenBloc>(
create: (context) => TokenBloc(),
),
BlocProvider<AuthorizationBloc>(
create: (context) => AuthorizationBloc(),
),
],
child: BlocBuilder<LanguageCubit, Locale?>(
builder: (context, lang) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
);
},
),
);
Таким образом, все остальные БлокПровайдер, которые вы используете для их создания, удаления, они вам не нужны, теперь, если вы используете Блокбилдер, BlocListeners любого Блока, у вас не будет никаких неудобств.
Ммм, я редактирую это, проверьте!
Что с ними может быть не так? В AuthorizationPageWidget я использую новый блок - AuthorizationBloc.
Все блоки, которые вы хотите использовать, должны быть в MaterialApp, с MultiBlocProvider, вы должны создать их там, вы это сделали?
Я добавил вопрос. Взгляни, пожалуйста. Разве MaterialApp не используется с основным блоком? его нужно дублировать на каждой странице? в MultiBlocProvider нужно подписаться на TokenBloc?
Ок, редактирую, смотри
Спасибо. Оно работает! Но по какой-то причине то, что я возвращаю в _childTokenBloc, не помещается на передний план. Я не вижу этого экрана, но по логам вижу, что он загрузился. Не подскажете, в чем может быть дело?