Flutter - How should be bloc communications in complex UI? - flutter

I want some advice on a topic which I'm curious about. What is the best way and best practice? I tried to draw a UI about this topic. I am using the flutter_bloc package.
Scenario: I have a list as shown in the picture and there are score buttons at the bottom. Buttons are not active without making a selection in the list. Buttons are active when I select an item from the list. When I press the score button, a score is written to the selected element in the list and the score buttons become inactive again.
This UI looks simple, but my problem is with a more complicated UI. So I will definitely use more than one bloc on a screen.
I wonder how do I get this communication between the blocs in the best way? Should I create a parent block on a top layer?

You should have a single bloc which will control the whole screen.
On your bloc state you could have a property which holds the selected item(or its index - really up to you here). Your point buttons will be enabled/disabled based on this prop through a BlocBuilder.
On a point button tap you just add an event like PointsAssigned(amount: 50) or FiftyPointsAssigned() - again up to you. This event will be mapped to a state where the points are attached to the selected item and will rebuild the UI through a BlocBuilder so your change will be reflected.

Multiple bloc can be used in same context. You can use MultiBlocProvider from flutter_bloc
Then, you can access both bloc data and communicate whatever you defined in the Bloc.
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<TodoBloc>(create: (BuildContext context) => TodoBloc()),
BlocProvider<PointBloc>(
create: (BuildContext context) => PointBloc()),
],
child: Scaffold(
......
),
);
}

It's hard to explain without knowing how your current codes look like. You don't really need additional bloc. Your Todo instance could have some sort of bool property onSelected.
Todo(
final String name;
final int point;
final bool onSelected;
Todo(this.name, this.point, this.onSelected);
)

Related

toggle todos checkbox trigger build function everytime

for RiverPod official todos sample, system triggers build function whenever I toggle checkbox item, is it a correct behavior ? Won't it cause performance issue? thanks.
As I know, state management has one purpose to avoid rendering widgets so often. Please correct me if any.
if you are watching your provider inside your build method then yes it rebuilds your entire build method. but if your want your the check box to only rebuild when necessary then its either (1) separates that into another class or (2) wraps that check box with Consumer Widget. something like:
Consumer(
builder(_, ref, __){
final checkboxProvider = ref.watch(yourCheckboxProvider);
return CheckBox();
}
)

How to update widget tree from another widget class - Flutter

I am facing problem to re-render the page when a variable changes in one class/widget (both parent and child widgets are stateful classes).
Here is how it goes:
I have three buttons in one class which changes a variable state (foodCategory).
int foodCategory = 0;
// down in the elevated button body - i am updating the variable
setState(() {
foodCategory = 1;});
While in the other widget, i am using this variable to perform certain actions:
for (var item in foodItems.values.elementAt(foodCategory))
GestureDetector(........ and so on...
However in the second snippet, the widget dose not know if there has been a change and it is not calling the buildcontext again...
I am not sure how to overcome this problem. I have tried valuelistenablebuilder but in vain. Maybe i dont know how to use it in the loop (i am using foodcategory as an int (iterator)).
it happned to be that i was sing valuelistenable builder in a wrong way.
It is easy. Just mark the variable and changes as valueNotifier. In my case, i needed to mark foodCategory as a valueNotifer.
Than, i needed to wrap the Widget (in my case column widget) as ValueListenableBuilder. This solved my issue.

Flutter How to create a DropDownFormField after the previous DropDownFormField has data

I'm new to Flutter. What I want to ask is when I have a DropDownFormField and have 3 values. How can when I select one of the 3 values I will display a new DropDownFormField with a dataSource associated with the previously selected value.
For example I have House, Hotel, Apartment => Select House => display new DropDownFormField has Room, Kitchen
Or Select Hotel => display new DropDownFormField has Single Room, Double Room
Are there any examples that I can refer to?
There are a few ways to do what you're asking, but let me restate your query using Flutter nomenclature which should help you find more info. (DDFF = DropDownFormField)
You have two widgets, and when the first widget changes state you want to show the other widget.
The simplest way to do this is to create a custom Stateful widget that will contain two DDFF (in a Column(), Row(), etc). A widget's state is the values in its variables. In the case of this custom widget, you want to know at least if a value was selected for the first DDFF and what that value is so you can change things about the second widget. So there is one state variable: String ddff1Value;
When you build() your widget you will decide based on the state what to show. You can change what is returned from your widget's build() function using if() or ternary operators. If ddff1Value==null (nothing has been selected yet), don't show the second DDFF.
You also want to know when your first DDFF widget selection has changed, and DDFF provides a callback called onChanged that will be called when it changes. When it changes you want to update (set) the state of your widget to store that change, then redraw your widget reflecting the change.
To set the state of a Stateful widget, you call setState(). In your first DDFF:
onChanged: (val) {
setState(() {
ddff1Value = val;
}
}
When you call setState(), Flutter will automatically redraw your widget afterward. That's it.
Create your custom Stateful widget
In the build() method, decide what to draw based on state
Use onChanged() to get values when DDFF changes
Call setState() to update your widget's state and redraw

Keep UI after emit state change Cubit Flutter

My Question: Can you keep built UI that was built by a state when another state is called?
Please correct me if I'm using the cubit pattern wrong. I have a unique example I'm trying to solve. I have the cubit set up and it's working as per documentation.
I have a screen where I have a horizontal list that is returned through cubit. Then based on the horizontal list returned if you click one of the items the cubit fetches a second list to display vertically underneath the horizontal list.
var _responseCategories = await _repository.postGetRootCategories();
emit(ShowCategories(state, _responseCategories));
var _responseCategoryItems = await _repository.postGetCategoryItems(_responseCategories[0].id);
emit(ShowCategoriesItems(state, _responseCategoryItems));
The ui has a bloc builder and processes the two states but when the one state is changed the UI for the first built state is then not there I understand why this happens but is there a way to stop it until I emit the state again. The UI decodes the states in a builder as follows:
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (state is ShowCategories) buildCategories(context, state),
state is ShowCategoriesItems
? Expanded(child: buildMenuItems(context, state))
: SizedBox.shrink(), //getMenuList(_activeSelection)),
],
);
If I'm using this wrong that's understandable I just want to know if there is a better solution to this to solve the problem as the category items are different per category and I don't need to fetch the categories every time the state changes.
The app is essentially a menu. The horizontal section is the categories of the menu 'I only need to load them once' and the vertical section is the items 'I need to load them when the user selects a category'. The items are different per category but the categories never change unless set by the server.
It seems like you have a master-detail view and your detail state is just a superset of the master-no-detail state.
You could derive your detail state from the master state and add more information to it (master-list, adding selected, details-list to the derived class) or you could just go with one state for both (master-list, selected, details-list) where some things aren't set when nothing is selected yet.
If your details view is really complicated, you could also create a whole new BLoC for it, with it's own logic and builder in the widget tree, then you can have totally different states.
But states from the same BLoC, you cannot opt to only rebuild a part of the tree below the builder.
(well, technically you can do anything, but there is no point in working around a pattern. If it does not fit, use a different one. And I think you can easily make it fit as described above)

Flutter: hide/show widget by key dynamically

How can we show/hide widget inside another widget in flutter?
I have list of question which are inside list view builder I want to hide questions on user answer selection.
if you have all equations in question[] and whether to show them in show[], you could place into listbuild
return (bool[index] ? Card(child:Text(question[index])) : Container())
This returns the card in bool is true and the empty (not displayed container) otherwise.
(I think the other answer would do the trick too)
Another option you can consider though is using the Visibility widget to wrap the "question" widget and toggle the visible property based on a bool. To make this (or the above solution) work, you'd want to update the value of this bool using e.g. setState on the method called when,as you say, "user answer selection" happens.
Of course, if you have a more complicated application it might make more sense to use Provider for state management and wrap all of this in a Consumer.