Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Effects triggered by unmounting a Widget #29

Open
oravecz opened this issue Oct 10, 2022 · 5 comments
Open

Effects triggered by unmounting a Widget #29

oravecz opened this issue Oct 10, 2022 · 5 comments
Labels
enhancement New feature or request

Comments

@oravecz
Copy link

oravecz commented Oct 10, 2022

I'm seeing my animation being applied when the widget is added to my UI, but how would I indicate the animation which should play when the widget is removed from the render tree?

@gskinner gskinner added enhancement New feature or request good first issue Good for newcomers labels Jan 9, 2023
@gskinner
Copy link
Owner

gskinner commented Jan 9, 2023

Good question. I'll have to look into this. If anyone wants to tackle this in the interim, it would be very welcome, even if it's just to throw some ideas at it.

@gskinner gskinner added the info needed Further information is required label Feb 7, 2023
@gskinner
Copy link
Owner

gskinner commented Feb 7, 2023

As a follow up question: How do you see this working, not in terms of specific implementation in the library but in terms of how you'd use it as a developer? Feel free to sketch some code examples.

@oravecz
Copy link
Author

oravecz commented Feb 7, 2023

Bear in mind I haven't thought about your internals and how they might be impacted by such an API...

Under typical conditions, the "remove animation" should happen automatically when Flutter determines my widget will no longer be rendered.

Text("Hello").animate()
  .fadeIn(delay: 300.ms, duration: 500.ms)
  .then()
    .slide(duration: 400.ms)
  .then(delay: 200.ms)
  .blur()
  .remove()
    .fadeOut(delay: 300.ms)

For example, I have a TextField inside of a Card that I expose (height animation currently) based on a user's tapping on a card. If they tap on the card again, I want the TextField to animate shut. In my code, I don't want to be concerned about any of this, I just want to be able to declaratively control whether my TextField is rendered or not.

Column(
  ...
  children: [
    ...
    if (selected) TextField().animate(
      effects: MyGlobalEffects.transitionIn,
      removeEffects: MyGlobalEffects.transitionOut,
    ),
    ...
  ]
),

@gskinner
Copy link
Owner

gskinner commented Feb 7, 2023

I don't think there's any way to interrupt or defer a removal like that in Flutter. That widget is simply not created in that build, so it and the Animate instance are disposed.

The easiest way to get something similar is to use target, but that requires that the "out" animation is just a reverse of "in".

foo.animate(target: selected ? 1 : 0).fadeIn().slideX()

Otherwise, I think you're going to have to do some state management, and the hardest bit will likely be avoiding a starting transition out. For example, this would mostly work I think, except it would run the "out" transition on the first build:

Animate(
  effects: selected ? [...] : [...],
  child: foo,
)

Maybe this could be solved with a more specific wrapping widget that maps the state change to appropriate effects for you? Something like this:

ToggledAnimate( // naming TBD
  toggle: selected ? true : false,
  inEffects: [...],
  outEffects: [...],
  child: foo,
)

Where the above would hold on the zero position for "inEffects" if it starts with toggle=false, then play when toggle=true, then switch to playing outEffects when toggle returns to false. You could then use VisibilityEffect to effectively get rid of the widget when it's hidden. I hope that makes sense.

@orestesgaolin
Copy link

I would like to see a syntax similar to what AnimatedSwitcher or AnimatedCrossFade provide but with the ease of flutter_animate e.g.:

Animate().toggle(
  index: 0, // 1, 2, 3....
  duration: 100.ms,
  inEffects: [FadeInEffect(), ScaleInEffect()],
  outEffects: [FadeOutEffect(), ScaleOutEffect()],
  builder: (context, index) {
    if (index == 0) {
      return Container(
        width: 40,
        height: 40,
        color: Colors.red,
      );
    } else if (index == 1){
      // and so on...
    } else {
      // 
    }
  },
)

This would make for a pretty generic variant of AnimatedCrossFade that typically allows only for switching 2 widgets. In case of removing a widget this would mean switching from actual widget to a SizedBox or something similar

@gskinner gskinner removed good first issue Good for newcomers info needed Further information is required labels Jul 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants