Давайте решим это шаг за шагом.
Ваш первый вопрос:
Нужно ли создавать необходимый BLoC специально для этой части пользовательского интерфейса?
Ну, это родственник ваших потребностей и вашего приложения. При необходимости вы можете иметь BLoC для каждого экрана, но вы также можете иметь один BLoC для 2 или 3 виджетов, в этом нет никаких правил. Если вы считаете, что в этом случае хорошим подходом является реализация другого BLoC для вашего экрана, поскольку код будет более читабельным, упорядоченным и масштабируемым, вы можете сделать это или, если вы считаете, что лучше сделать только один блок со всеми внутри, вы свободны к этому тоже.
Ваш второй вопрос: и как?
В вашем коде я вижу только setState
вызовы в _buildAddSection
, поэтому давайте изменим это написание нового класса BLoc и будем обрабатывать изменения состояния с помощью потоков RxDart .
class LittleBloc {
// Note that all stream already start with an initial value. In this case, false.
final BehaviorSubject<bool> _descriptionSubject = BehaviorSubject.seeded(false);
Observable<bool> get hasDescription => _descriptionSubject.stream;
final BehaviorSubject<bool> _checklistSubject = BehaviorSubject.seeded(false);
Observable<bool> get hasChecklist => _checklistSubject.stream;
final BehaviorSubject<bool> _locationSubject = BehaviorSubject.seeded(false);
Observable<bool> get hasLocation => _locationSubject.stream;
void changeDescription(final bool status) => _descriptionSubject.sink.add(status);
void changeChecklist(final bool status) => _checklistSubject.sink.add(status);
void changeLocation(final bool status) => _locationSubject.sink.add(status);
dispose(){
_descriptionSubject?.close();
_locationSubject?.close();
_checklistSubject?.close();
}
}
Теперь я буду использовать этот BLoc в вашем виджете. Ниже приведен полный код метода build
с изменениями. В основном мы будем использовать StreamBuilder
для создания виджетов в дереве виджетов.
final LittleBloc bloc = LittleBloc(); // Our instance of bloc
@override
Widget build(BuildContext context) {
final eventBloc = BlocProvider.of<EventsBloc>(context);
return BlocBuilder(
bloc: eventBloc,
builder: (BuildContext context, EventsState state) {
return Scaffold(
body: Stack(
children: <Widget>[
Column(children: <Widget>[
Expanded(
child: ListView(
shrinkWrap: true,
children: <Widget>[
_buildEventImage(context),
StreamBuilder<bool>(
stream: bloc.hasDescription,
builder: (context, snapshot){
hasDescription = snapshot.data; // if you want hold the value
if (snapshot.data)
return _buildDescriptionSection(context);//we got description true
return buildAddSection('description'); // we have description false
}
),
_buildAddSection('location'),
_buildAddSection('checklist'),
//_buildDescriptionSection(context),
],
),
),
]
),
new Positioned(
//Place it at the top, and not use the entire screen
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(
actions: <Widget>[
IconButton(icon: Icon(Icons.check),
onPressed: () async{
if(this._checkAllField()){
String description = hasDescription ? this.descriptionController.text : null;
await eventBloc.dispatch(AddEvent(Event(this.eventNameController.text, this.eventDate,"balbla", description: description)));
print('Saving ${this.eventDate} ${eventNameController.text}');
}
},
),
],
backgroundColor: Colors.transparent, //No more green
elevation: 0.0, //Shadow gone
),
),
],
),
);
},
);
}
И не более setState
звонков в вашем _buildAddSection
. Просто нужно изменить switch
заявление. Вызовы changes...
обновят потоки в классе BLoc, и это сделает перестройку виджета, который прослушивает поток.
switch(sectionName){
case('description'):
bloc.changeDescription(true);
break;
case('checklist'):
bloc.changeChecklist(true);
break;
case('location'):
bloc.changeLocation(true);
break;
default:
// you better do something here!
break;
}
И не забывайте вызывать bloc.dispose()
внутри WidgetState dispose
метод.