flutter_animate icon indicating copy to clipboard operation
flutter_animate copied to clipboard

Animate only if the widgets are inside the ViewPort or visible portion of the screen [Web]

Open TechSatya opened this issue 2 years ago • 6 comments
trafficstars

I have multiple distinct widgets inside a column and every widget has some animation effects, upon the user reaching the respective widget by scrolling they will animate which I want, but before that, if they are hidden from the user's view part means not inside the viewport, then they will not animate.

But here the issue is they all are animating at once after the website loads.

Reference - https://www.stryve.online/

TechSatya avatar Sep 15 '23 08:09 TechSatya

@gskinner any input, please?

arithmic-satya avatar Sep 22 '23 08:09 arithmic-satya

Sorry, I'm not totally clear on which are you asking for?

  1. It animates as soon as it is instantiated.
  2. It animates when it scrolls into view.

gskinner avatar Nov 20 '23 22:11 gskinner

@gskinner All the animations are instantiated at once after the website loads, so when I reach the animation attached widgets by scrolling down, nothing happens as those have already been instantiated in the website's initial load.

arithmic-satya avatar Nov 21 '23 12:11 arithmic-satya

Yes it should be fine to animate only once it is visible. The first items list animate. The second, out of screen, doesn't.

class Page8 extends StatelessWidget {
  List<Widget> items = List.generate(
      3,
      (index) => Padding(
            padding: const EdgeInsets.all(8.0),
            child: Container(
              width: 100,
              height: 100,
              color: Colors.amber,
              child: Text('Item $index'),
            ),
          ));

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
        child: Column(children: [
      Row(
        children: [...items]
            .animate(interval: 600.ms)
            .fadeIn(duration: 900.ms, delay: 300.ms)
            .shimmer(blendMode: BlendMode.srcOver, color: Colors.white12)
            .move(
                begin: Offset(MediaQuery.of(context).size.width, 0),
                curve: Curves.easeOutQuad),
      ),
      const SizedBox(
        height: 900,
      ),
      // Don't animate when it become visible
      Row(
        children: [...items]
            .animate(interval: 600.ms)
            .fadeIn(duration: 900.ms, delay: 300.ms)
            .shimmer(blendMode: BlendMode.srcOver, color: Colors.white12)
            .move(
                begin: Offset(MediaQuery.of(context).size.width, 0),
                curve: Curves.easeOutQuad),
      ),
    ]));
  }
}

ljoly83 avatar Dec 08 '23 15:12 ljoly83

It might be possible to create an Adapter that would handle this. I'm not sure that's the best choice, since adapters are intended to control the animation position directly, whereas this would just be playing/pausing. Sketch:

foo.animate(
  // names TBD
  // debounce = time to delay before playing
  // threshold = how much needs to be onscreen?
  adapter: OnScreenAdapter(debounce: 500.ms, threshold: 1.0)
).fadeIn()

Another option would be a simple helper class that wraps the child, and starts a controller when the item becomes visible on screen. This would likely be messier though, as it would require creating the controller externally, with all the baggage that involves (state, disposal, etc).

A final approach could be to have a helper method that can be called from (or passed to) onInit, that would manage it for you. Sketch:

// getOnScreenWatcher would return a function that accepts the controller from onInit
// pauses the animation, and sets everything up.
foo.animate(onInit: getOnScreenWatcher(debounce: 500.ms, etc)).fadeIn()

I'll add looking at these options to my backlog, but feel free to take a stab at a PR.

gskinner avatar Jan 31 '24 00:01 gskinner

i dint understood could you please explain how to acheive this behaviour

itanvation avatar Mar 21 '24 11:03 itanvation