Category Archives: flutter

State Management (no cubic, bloc)

We start off with Page 1. Page 1 has two containers with blue. We go to Page 2 in order to change these colors via radio buttons. When we come back to Page 1, the colors have changed. This is how state is shared between two pages.

main.dart

Now, in Page 1, we have two properties. firstSquareColor and secondSquareColor. They are both set to false.

page1.dart

We have Containers that display blue or pink depending on this bool. For false, we display blue for both booleans. We look to Page2’s radio edits in order to know how to color our Containers.

At the very bottom of page 1, we have a button that goes to page2 in order to change radio btns:

It calls _navigateNextPageAndretriveValue in order to use Navigator to navigate to page 2.
Now look at this function _navigateNextPageAndretriveValue:

Basically its an async function because we wait for the results that returns from when the next page (page2) pops.

So let’s see what happens when at page2.

We have two properties to maintain the bools.

page2.dart

So we have a switch that takes this value. When the user clicks on the radio button to switch bool, firstValue and secondValue will be updated due to setState.

page2.dart

Now, when you’re ready, you push the save button. Remember in Page1 where we have the _navigateNextPageAndretriveValue function?
That function is currently awaiting Navigator.push(…). Our page2 is the result of that. And once we Navigator.pop here, with our list of firstValue and secondValue, this list will be returned to _navigateNextPageAndretriveValue.

Now these two bools will be in nextPageValues.

Then in Page 1, we simply set its properties to the values presented in nextPageValues array.

Source

main.dart

page1.dart

page2.dart

Log In Animation v0

ref –

  • http://chineseruleof8.com/code/index.php/2021/05/06/15084/
  • http://chineseruleof8.com/code/index.php/2021/05/02/fade-and-slide-transition-in-flutter/
  • Download Source
  • result

We start off at main.dart. Its just a standard Scaffold that Navigates a SecondPage (stateful widget) class onto the screen.

When SecondPage appears, we need to keep track of state because we need an AnimationController called _transitionUpAndFadeInCtrller to do some animation. We use a Timer to wait 100 milliseconds before we execute our animationController. Hence, this means that the animation is executed when the screen appears.

SecondPage.dart

We then pass the _transitionUpAndFadeInCtrller into another child class Bottom that we want to animate.

SecondPage.dart

In that child class we’re going to animate a Slide Transition. We specify how it will animate by saying it will begin at 20% from the bottom (0, 0.2). In this case, positive number at Y moves it down. Negative number moves it up.

example:

1 Y means we start from below the x-axis.
so 0.5 means we push 50% of the height down. Halfway of the box is on x-axis.
and then we end up with full height of 280 after animation.
-1 Y means we start from TOP of the x-axis.
so -0.5 means we start from above the x-axis.

We animate the container up to the original position at (0,0).

Bottom.dart

So the animation controller specified that the animation duration will be 1 second. The animation itself is a SlideTransition that tweens from (0, 0.2) to (0,0) on a container with text and buttons.

Let’s also add a fade transition to it. We put the fade transition as a child of the slide transition. We give the animation controller as opacity because it would animate opacity 0 to 1 in the duration specified by the animation controller.

Bottom.dart

So when the screen appears, we do the slide Transition along with the fade transition for a container that has text and buttons.

start-up-animation

Adding in an Animation for future usage

So we have a nice animation going when the screen appears. Now we want to add animation so that in the future, we can animate the container of text and buttons off the screen like this:

slide-to-left-animation

The way to do this is to first create a separate animation controller. We then initialize it to AnimationController with vsync referencing this, and a duration in milliseconds.

Bottom.dart

bPushed and animationStatusListener

a) the boolean bPushed
b) and animateEnterPwdController.addStatusListener(animationStatusListener).

The status listeners tells us when the slide away animation has completed. It will work together with bPushed. So what ends up happening is that when the button in our container is pushed, we will animate the container with the text and button OFF SCREEN using animateEnterPwdController. When the animation is complete, our bPushed will be set to true. Once it’s true, we create the stagger animation list.

Bottom.dart

Remember that when state is changed, the whole instance is refreshed. Thus, the build function will run, and we get to re-draw this part of the DOM tree with the stagger animation list.

The slide away animation using animateEnterPwdController

We wrap animation AROUND the UI container.

Bottom.dart

Notice that there is two animations wrapped around textAndButtonsContainer:

1) introAnimateCtrller
2) animateEnterPwdController

Understand that the contents are visible because introAnimateCtrller animated them onto the screen. It has executed already and is finished. We then use animateEnterPwdController to animate this container OFF the screen. This is the simple logic to it. The animation itself is very straightforward as it uses a Tween on a SlideTransition to move the container off screen to the left.

Once the container animates off screen, our listener will trigger:

We simply do two things. Set bPushed to true so that state has changed. This means our build function will be called again with the bPushed of true, which then draws the staggered animation:

Notice

We’re basically reversing the intro animation, which will then move toward and fade away from opacity 1 to 0.

Flutter Staggered Animations

ref – https://pub.dev/packages/flutter_staggered_animations/

result (.mov)

In your pubspec.yaml file, include

We use AnimationConfiguration.toStaggeredList with a duration of Duration(milliseconds: 1375).

We then fill in the childAnimationBuilder, which is the specified way on how to animate each widget in the List. The idea here is that we wrap this widget with FadeInAnimation and SlideAnimation. It’s a combination effect.

Hence, what we’ve stated in childAnimationBuilder is that for each child widget, we want to apply the slide and fade in animation to each widget.

This is for fade in on lists.

Full Code

Fade and Slide transition in Flutter

ref – https://www.youtube.com/watch?v=xIX9Bo_yjvo
https://medium.com/codechai/flutter-animation-basics-explained-with-stacked-cards-9d34108403b8

First we have to refactor our class into a StatefulWidget.

1) extends StatefulWidget
2) @override createState()
3) extends State
4) with SingleTickerProviderStateMixin

When you add your SingleTickerProviderStateMixin, it tells Flutter that there is some animation in this widget and this widget needs to notified about the animation frames of flutter.

Animation controller is one of the basic things necessary for creating magic in flutter. You can imagine this as the dictator of the animation on screen. It contains the duration of the animation and so it will split out values between 0 to 1 based on the duration and the ticker value.
Controller value is 0 -> Start of your animation
Controller value is 1 -> End of your animation

vsync property is related to the Ticker and if the stateful widget has the Mixin, you can pass this to this property.
Animation with just the controller is possible when your animated value is also from just 0 to 1. You can pass the controller value to the widget and start the animation by calling controller.forward()

Tween

Short for in-betweening, the process of generating intermediate frames between two images to give the appearance that the first image evolves smoothly into the second image.

Creating the in-between values is the responsibility of Tween. Tween takes a begin ,end, properties and to create a Animation variable we should use the animate method and pass the controller.

When you call animation.forward() it will produce a smooth animation from the begin Offset value to end Offset value.

Fading in a Text

Wrap some padding around it using a Container

Now let’s start a fade transition. We pass in our animation Controller for the opacity. Our animation controller has an animation time of 1500 milliseconds. Thus, it will animate the opacity from -1 to 0 in 1500 milliseconds.

Run the project and you’ll the text have this fade effect.

Transition the Text

Let’s remove the fade transition from our Text Container. Our Text container should simply be:

We wrap a SlideTransition like so:

child class

So in order to make this work, we have a child class and that houses Text and an Image.

As you can see, it references an injected animation controller. The animation controller in the parent class holds state:

SlideTransition – for position property we assign it a Tween. The tween takes the animationController in order to animate.

FadeTransition – for opacity, we stick in the animation controller, which says duration should be 1.5 seconds.
However, we decide to forgo this feature and just use transition.

In the parent class, we use it like so:

Now when the animation starts, the text will transition from the left and come in towards the right.

Moving the button up

So now using the same tactic, we create another class called Bottom, that will reference the parent class animationController. It will have some static UI widgets which we will animate.

For its build function, we return a slide Transition.

The position needs a Tween. We want it to come from bottom off screen

So we know that it will slide something from offscreen (x is 0, y is 1) up to original position.
That something is a container that holds text:

hm 3 references

1) Fetching Random Name from API using Dio and Bloc

https://blog.usejournal.com/flutter-http-requests-with-dio-rxdart-and-bloc-da325ca5fe33
original source – https://github.com/jhomlala/randomuser

Updated source

2) Carousel

ref – https://pub.dev/packages/carousel_slider

First, we have an array of image URLs where images are located.

code for imgList

We take that array and for each item, we create a Container, with another Container as the child.

The child Container has a ClipRRect, which has a Stack.

This Stack means it contains an Image, with a Positioned Widget.
The Positioned widget has a Container and fits text inside of some padding.

Thus, this completes our List of Widgets.

The code for imageSliders

We then stick this list of Widgets to the items property of CarouselSlider.

code for CarouselSlider

Then in your class, you use it like so:

VerticalSliderDemo class

3) Navigating from one page to another

ref – https://flutter.dev/docs/cookbook/navigation/navigation-basics

Cubit and Bloc simple example

ref –

  • https://resocoder.com/2020/08/04/flutter-bloc-cubit-tutorial/
  • https://medium.com/flutterando/cubit-a-simple-solution-for-app-state-management-in-flutter-66ab5279ef73
  • http://chineseruleof8.com/code/index.php/2021/04/14/beginning-bloc-for-flutter/
  • http://chineseruleof8.com/code/index.php/2021/04/15/working-with-flutter-bloc/
  • https://github.com/irvine5k/cubit_movies_app/

A Cubit is the base for Bloc (in other words Bloc extends Cubit).

Cubit is a special type of Stream which can be extended to manage any type of state .

A functions is generally that something you create to do some orders as you want and this function will be achieved my orders when I would CALLING IT so it can’t achieve anything without any call from me . something like when I call KFC to order some food the function here is calling the restaurant to order my food because the restaurant can’t order food to me without calling it.

It replaces events in the bloc architecture. Originally, UI actions create events. Events get mapped to State. And we return certain state to update the data to be drawn in the UI.

However, instead of mutating individual fields, we emit whole new MyState objects. Also, the state is in a class separate from the one responsible for changing the state.

Importing Cubic

pubspec.yaml

State

A rule of thumb is to always build out the state class(es) first. So, what kind of WeatherState do we want to have?

We have the abstract class WeatherState to denote top of hierarchy.

We then create different Weather States that implements this abstraction. In our case:

WeatherInitial – This WeatherInitial state will indicate that no action has yet been taken by the user and that we should display an initial UI
WeatherLoading – we are waiting for the weather to arrive from its web api
WeatherLoaded – the data has arrived!
WeatherError – internet connection broke somehow.

We also override annotation operator ==. This is because UI updates when state are different. Flutter will do a comparison between different states. If the states are different, update the UI. If they are the same, don’t do anything. Thus, for our Weather state, we need to override this to let flutter do the comparison.

If the two states are identical, then UI won’t do anything.
If the incoming object is of the same state (say WeatherLoaded) and the state’s weather object is the same, then we return true and UI won’t update.

But if either:
– the Object o is of another state
– the weather has changed

then we return false, to let Flutter know that the state have changed.

Always override equality of the state classes. Bloc will not emit two states which are equal after one another.

Thus, if we do not override equality, Bloc will ALWAYS update the UI and it degrades performance.

Cubit

Having finished our work on the state, let’s implement the WeatherCubit that will perform logic such as getting the weather from the WeatherRepository and emit states.

So we extend from Cubit

We ctrl + click Cubit to see what’s going on underneath. We see that it’s an abstract class that uses a StreamController. This is mentioned in our earlier tutorials on basic blocs and stream:

  • http://chineseruleof8.com/code/index.php/2021/04/14/beginning-bloc-for-flutter/
  • http://chineseruleof8.com/code/index.php/2021/04/15/working-with-flutter-bloc/

A stream can only take one type, and we see that Cubit takes on the state that we specify in the type bracket.
The StreamController instance then broadcasts it and it will be sink.add, or stream.listen accordingly. But when using Cubic, all that details are hidden away.

Do take note of the constructor. It takes a state as parameter.

Hence that is why in our initialization code, we put WeatherInitial() instance because it assigns the initial state to Cubit.

We then have our a weatherRepository instance that gets the data from a web api.

Notice that we don’t need to override mapEventToState here like we do in bloc architecture.
That is because in Cubit, there is no events. We only have functions that trigger state change.

Hence, in our case, we call getWeather to asynchronously get data. But before it does, we first emit a WeatherLoading state instance. This state is to trigger a circular indicator in our UI, as will be shown later.

Then we do the async operation and get the weather data. After receiving this data, we emit that state to be loaded, along with the weather data itself.

The states then get reflected on the UI through BlocBuilder:

weather_search_page.dart

Running the App

In the very beginning, we have this:

It’s a class that extends StatefulWidget. We need to override StatefulWidget’s abstract method createState. createState returns State. Thus, we need to create a class that extends from State. We name it WeatherSearchPageState. The type of State is WeatherSearchPage.

We then override the build function, which is used to build the UI.

When we run the app, we get the log messages like so:


flutter: weather_search_page.dart – WeatherSearchPage – createState
flutter: weather_search_page.dart – state: Instance of ‘WeatherInitial’
flutter: weather_search_page.dart – WeatherInitial state –> returning buildInitialInput() UI

We get WeatherInitial state because in WeatherCubit, we initialized state it WeatherInitial():

The way how the UI is implemented is. Our UI is organized in such a way that whenever a state is such, we return the proper UI widgets.

Then when we put in a city for weather, we start at the cubit. It uses the weather repo to do its async operation. Once its done, it emits a state. This state then is caught in the UI where weather_search_page.ldart sees that its a WeatherLoading.


flutter: weather_cubit.dart – weather is loading…
flutter: weather_repository.dart – getting weather for shanghai
flutter: weather_search_page.dart – state: Instance of ‘WeatherLoading’
flutter: weather_search_page.dart – WeatherLoading state –> returning buildLoading() UI

Then few seconds later, in weather_cubit, we receive weather data. It will emit WeatherLoaded.
Now, Cubit will do a comparison between WeatherLoading and WeatherLoaded in its operator overloaded ==.


flutter: weather_cubit.dart – received weather data!
flutter: weather_state.dart – WeatherLoaded – comparing Instance of ‘WeatherLoading’ and Instance of ‘WeatherLoaded’
flutter: weather_state.dart – DIFFERENT state, update UI NOW!

When the states are different, we update UI.


flutter: weather_search_page.dart – state: Instance of ‘WeatherLoaded’
flutter: weather_search_page.dart – WeatherLoaded state –> returning buildColumnWithData() UI

Working with Flutter Bloc

ref – https://pub.dev/packages/flutter_bloc

Events

Events are triggered due to some user action from the UI layer. Events can be represented via hierarchy by using abstract classes.

For example, in the app we are going to build today, there are three events, FetchWeatherEvent, ResetWeatherEvent, RefreshWeatherEvent. They all extend from WeatherEvents.

They are triggered in WeatherView. In our UI, say we have a handler called onRefresh. When the refresh button is clicked, it will execute it like so:

Notice that it uses BlocProvider to add our Event to the event stream’s sink. This is essentially what’s happening when we call BlockProvider.of(context).add(…).

RefreshWeather extends from WeatherEvents, as are other classes.
Thus, on the UI layer, we put events on the event stream in such ways.
When the event arrives on the event stream, we have BlocObserver.

The idea is that we pass the Bloc and Event into our BlocObserver.
BlocObserver will then call weatherBloc’s mapEventToState with this particular event.

mapEventToState is an abstract function in our weatherBloc, which yield states to this particular event. Yielding state means we are sending the state in the counter stream back to the UI layer.

Notice that we await a weather repo to get the weather from a web API. Then we have received it, we just yield the state class WeatherLoaded with the weather data. Of course we can yield instances of other state classes that implements the State abstract class, which is used to put up say an indicator or stop an indicator.

weatherState.dart

Notice WeatherLoaded has a weather property that holds on to this new data.
We also override props because our abstract class WeatherStates extends Equatable.
In order to see if this instance is equal to another, we need to put our weather object in the props array
so Equatable can do the comparison

Okay, so now from the WeatherBloc, we have yielded the WeatherLoaded instance along with the weather data, now what?

We come back to simpleBlocObserver and hit the onTransition.

SimpleBlocObserver.dart

So this means that we’re currently on the WeatherEmpty state
The event passed in is fetchWeather
Because Event FetchWeather, weatherBloc yields WeatherLoading…that is why our nextState is WeatherLoading.

When the data arrives the state will be WeatherLoaded. But first! Let’s see what happens to the UI when we our state is on WeatherLoading.

In our weather.dart, our BlocConsumer’s listener will be activated.

BlocConsumer

BlocConsumer exposes a builder and listener in order react to new states.

BlocConsumer is analogous to a nested BlocListener and BlocBuilder but reduces the amount of boilerplate needed.

BlocConsumer should only be used when it is necessary to both rebuild UI and execute other reactions to state changes in the bloc.

BlocConsumer takes a required BlocWidgetBuilder and BlocWidgetListener and an optional bloc, BlocBuilderCondition, and BlocListenerCondition.

If the bloc parameter is omitted, BlocConsumer will automatically perform a lookup using BlocProvider and the current BuildContext.

in our case, look aa builder property. In it, its if-else has a condition where if state is WeatherLoading, then it returns an instance of a Center Widget. In it, it has a CircularProgressIndicator which will then run on the UI.

weather.dart

So now our circular indicator is running, we’re also fetching data from the web api.

weatherBloc.dart

Once the data comes back, we yield WeatherLoaded with the data. The BlocConsumer’s state changed to WeatherLoaded and it simply updates the UI.

In our particular case, we update our refresh control, and give it a ListView where it calls DisplayWeather to put all the text and new data onto the screen.