In this article, I’ll use a simple app to demonstrate building an UI that can change without requiring a complete rebuilding of all widgets on the screen.

In the app demo below, the Floating Action Button (FAB) displays the value of a counter variable initialized to zero before the build is called for the first time.

With every double tap on a card, the value of the variable is incremented by one but it doesn’t reflect on the FAB, verifying that the UI has not been rebuilt. The third card, on the other hand, calls setState() apart from incrementing the value, prompting a UI rebuild and the new number(three) is now displayed.

App demo

The Architecture

The app follows principles of reactive programming and is built on the BLoC pattern using streams for data propagation.

The app flow

The UserBloc has streams that receive inputs from widgets and provide updates to those widgets that listen on these streams. We can also have separate streams that handle input and output and in this way we can add logic to ensure that only the selected and processed inputs enter the output stream.

The UserBloc is made available to all the widgets through a BlocProvider at the top of the widget tree, which is just a Stateful wrapper for the UserBloc(allowing the disposal of resources, like closing of streams).

The top widget is made the child of BlocProvider

The Code

The card widgets are subscribed to the respective streams and the bool value passed into them by the onDoubleTap() method determines whether they are displayed or not. If the value’s false, the widget is removed from the UI.

The application assumes the client id to be “1” for illustration purposes but can be replaced with “client.id”.

Ignore the sinkCounter for now

When a double tap is encountered, two courses of action are taken.

First, a Message object with “false” value and the user id is passed into the stream.

Second, a method is called in the ClientModel class to modify the status parameters. These methods, in turn, call the database methods to persist the data.

Whenever the application is restarted, StreamBuilder checks the database for an existing value as its initialData

The updateClient method is called on the database

Forcing A UI Rebuild

Up to this point, the FAB doesn’t reflect the true value of the local counter variable. To make it do so, we’ll have to force the widgets to be built again.

This is accomplished by integrating a “non-reactive” card into the UI. This card(the third card) calls setState() to change parameters and refresh the screen.

As a result, the FAB now has the number “3” displayed on it.