felangel / bloc

A predictable state management library that helps implement the BLoC design pattern
https://bloclibrary.dev
MIT License
11.84k stars 3.4k forks source link

question: Using Implicit animation on page creation #3115

Closed paulinventome closed 2 years ago

paulinventome commented 2 years ago

I hope I describe this correctly.

I have a page which creates different widgets depending on the state of category display

if (state is CategoryLoading) { return Scaffold( key: dKey, appBar: AppBars.tbAppBar(context, "Browsing"), body: CommonUI.tbSpinner(context, "Fetching Main Categories")); } else if (state is CategoriesLoaded) { return Scaffold( key: dKey, appBar: AppBars.tbAppBar( context, state.categoryresult.header.name.toString()), body: renderListView(context, state)); } else if (state is CategoryError) { return Scaffold( key: dKey, appBar: AppBars.tbAppBar(context, "Category Error"), body: TbError( title: "Category Error", message: "There was an error in locating the categories for this class. ", )); }

This works okay. The renderListView renders out the categories but i need to have them animated as they are drawn, a quick scale as they pop in. In my bloc i emit CategoriesLoaded but i need some other way to create a state change after the tree is built.

I thought perhaps i could emit another state after the CategoriesLoaded but the BlocBuilder has to build something for every state. I tried a BlocConsumer with a listener AND a builder, but same issue.. I cannot fire off a state change for the listener to pick up without triggering a rebuild in the builder part.

I know this is my lack of knowledge but i've googled Bloc and Animation and found very little.

I want to trigger the animation as the page is built, seems like a simple ask. Maybe the Implicit animation approach isn't the way to achieve this?

Can anyone point me towards docs or samples that might help me work this out?

Kindest Paul

felangel commented 2 years ago

Hi @paulinventome 👋 Thanks for opening an issue!

Can you please share a link to a minimal reproduction sample that illustrates the issue you're facing? I'm happy to take a closer look and open a PR with suggestions. Thanks! 🙏

paulinventome commented 2 years ago

Hi @felangel

Thank you so much for looking at this. I will need to build a minimal repro case as the app i'm in is large and complex. I will do this tomorrow my time.

I have a feeling this is more about not knowing the correct approach with Bloc hence i added it to documentation rather than a problem

I have an API building pages via BlocBuilder and based on states. This has been working great.

I have managed to use setState on the page widget to do some animation but it feels like it's not the correct way to do it.

So it's about how to trigger and manage animations via the Bloc library. An concept. A page triggers an API call, gets a list of items. The bloc emits the state change with the items and a list builder can generate the list on the screen. Works great. But if i want that list of items to animate as it appears on screen. Confusion.

Using the Implicit animations and an AnimatedContainer i see no way to trigger that with Bloc. Instead i set a timer on the stateful page and then that changes values via State and i can sort of see some animation. But this happens all at once.

It's a case of how do i get these state changes via Bloc events. And i am sure this is my lack of knowledge.

I will build a sample and hope that illustrates what my intent is

Kindest Paul

narcodico commented 2 years ago

Hi @paulinventome 👋

What you're probably looking for is AnimatedList or SliverAnimatedList. They allow animating insertion/removal of items. They don't support animating the initial rendering of items out of the box, so that's something you'd need to work it out.

Hope that helps!

Gene-Dana commented 2 years ago

👋 hi there ! I imagine a bloc listener may be of help here - you can use the listener to listen for a specific event/state and then trigger what you'd like. You can see an example here:

https://github.com/felangel/bloc/blob/033c95260e8f638a32a1733cfd2575e2480e2cd3/examples/flutter_weather/lib/weather/view/weather_page.dart#L37-L40

Note: A BlocConsumer is a combined listener and builder

For sure, if you have any repo you can share, we can better assist you with your questions, and hopefully point you in the right direction!

paulinventome commented 2 years ago

Thank you everyone. I got tied up with client work so not had a chance to do a repro but i will as soon as i can.

@narcodico Yes, there is a chance that AnimatedList might achieve what i am looking for although i would also like to understand the bloc perspective more

What i realised is that I started with an early version of Bloc in my app and have been updating but just updating to make it work. What i am realising actually is that there have been shifts in the best practises which i am probably not doing correctly. So i am needing to go back to the docs and start again to wrap my head around.

This issue is one of them.

If i have a BlocConsumer with a listener and builder i don't believe it is possible for a state change to be consumed by just one?

So if i have a state change of ItemsLoaded which holds the list of items to be built. I cannot after that has completed fire off another state change which triggers a UI animation. Because that second state change would be consumed by the builder and therefore trigger a rebuild of the widget tree.

Am i right in saying that every state change forces a build?

Kindest Paul

narcodico commented 2 years ago

If i have a BlocConsumer with a listener and builder i don't believe it is possible for a state change to be consumed by just one?

You can control that using buildWhen and listenWhen on the BlocConsumer.

Am i right in saying that every state change forces a build?

Yes, as long as buildWhen evaluates to true, which by default it does.

felangel commented 2 years ago

Closing for now but feel free to comment with any additional questions and I'm happy to continue the conversation 👍