skip to Main Content

In Flutter, I can use animateTo on the scroll controller to cause my grid view to scroll to zero offset over a set duration if I am some way down the view, but the animateTo method can be cancelled if the user does a scrolling action during the course of the scrolling to top animation (Notice in the documentation that it says ‘An animation will be interrupted whenever the user attempts to scroll manually, or whenever another activity is started, or whenever the animation reaches the edge of the viewport and attempts to overscroll.’). Not only that, but if I put animateTo into an anonymous function for onTap in a GestureDetector, and then put a function right after it, that second function still gets executed even if the animateTo method is stopped because of the user doing a scrolling action before the animation finishes.

This is problematic for my situation. If the grid items are for written posts, I want the user to be able to click on the grid item, have the grid view scroll to top, fade out the grid view, and fade in content from the written post. Scrolling to the top before switching out the grid view for the content of the written post is important as I would like some header icons to animate and then disappear when the user scrolls some distance down, and for the header itself to move up after that header icon animation is triggered, resulting in more space for viewing content. To get the header icons back, the user would have to scroll up to a certain threshold, and then an appearance animation would play and the header icons would be back. So the user being able to cancel the animateTo method might result in those those icons not coming back when I want them to do so. BUT since the function right after the animateTo method still gets executed even if the animateTo method is cancelled, subsequent function(s) for fading out the grid view, removing its widget, replacing it with a new widget (that would have content from the written post), would still get executed (potentially leaving me with a new scroll controller at 0 but without those header icons??). Is there a way to scroll to the top of a grid view over a set duration (which duration would be set by a variable of mine that would change depending on the distance to be traveled in the scrolling to top) in a way that the user can NOT cancel? If there is no way to do this, then a consolation prize would be some way to prevent the subsequent function(s) for onTap of the Gesture Detector from being executed if the user stops the animateTo method from completing.

The jumpTo method will not work as it is not animated. I would have the name of my non-profit also shift and move as one scrolls down, so the icons getting back to an original position is also not the only thing dependent on scrolling back up.

2

Answers


  1. Chosen as BEST ANSWER

    With the help of comment(s) of @pskink, I was able to solve my problem with the use of IgnorePointer. I wrapped the screen Scaffold widget with IgnorePointer, set the ignoring value of IgnorePointer to the variable scrollAnmInProgress, set scrollAnmInProgress to true, did the scroll to top animation, and then set the scrollAnmInProgress value back to false. Here is some of the code that I used in the onTap method of the GestureDetector:

    scrollAnmInProgress = true;
    var scrollToTopTime = computeScrollToTopTime1(screenWidth,  _entriesGridScrollController.offset);
    var scrollToTopTimeInt = scrollToTopTime.round();
    controller.animateTo(0,
      duration: Duration(milliseconds: scrollToTopTimeInt),
      curve: Curves.easeInOut);
    var scrollAnmIgnorePointerTimer =
      Timer(Duration(milliseconds: scrollToTopTimeInt), () {
    scrollAnmInProgress = false;});
    

    The computeScrollToTopTime1 function was there to give me a duration time (whose value would depend on how much scrolling would have to be done) for the duration part of the animateTo method, which time was rounded to convert from a double type to the int type that is wanted by 'duration'. With that duration time in hand, I then started the scroll to top animation and I set a timer for the same time period as the duration of the animateTo method. When that timer was done (just at or around the time that the animateTo method finishes), the ignoring boolean value of IgnorePointer was set back to false, and the user could then scroll or do other things in the app. In the final app, I would likely call additional function(s) that would immediately set IgnorePointer's ignoring boolean value back to true to have the user wait for the fading out of the content and the fading in of new content.


  2. I’m going to play devil’s advocate here with an answer you may not like. You could use IgnorePointer or such to prevent user interaction while you’re performing a scroll which should solve your immediate problem, but that seems… tangential to the actual problem.

    The problem as I see it is that you’re trying to manually animate a ton of different things that will result in a hugely complicated app that is very fragile and potentially user-unfriendly. If there’s ever a bunch of animations that a user might want to manually cancel by scrolling in your app, there’s a good chance those animations don’t belong.

    If you do animate as described this could result in very difficult to diagnose bugs (e.g. what happens when the app is closed mid-scroll), weird scenarios, and a bunch of potential pitfalls that aren’t immediately apparent. The example that comes to mind first is what would happen if the user immediately presses back from the written post – if you’ve manually animated each step of the "to the post" animation, for a good UX you should probably animate the "from the post" animation as well, which sounds like it could be pretty complicated.

    What I’d recommend is simplifying the UX of the app to the bare minimum – simple animations, full-page fade-in and fade-out, etc, unless there’s a huge need for a custom animation. From my experience 99% of users will simply not care if there are fancy animations so long as the app functions well. Get things working first, and then if you have tons of extra time on your hands, then you can play with more custom animations. As a developer, I sometimes fall into this trap too, but experience has taught me that people use apps because they work, not because they have fancy animations.

    Now, if you feel like you really do need some animations of icons, footers, headers, etc, I’d recommend you lean on the built-in hero animations as they’re very simple to use and surprisingly functional, and if needed you could use a package such as flutter villains that enables additional animations post-page-render. And if you need headers that appear and disappear with scrolling, flutter has a mechanism in that with flutter slivers. Combine slivers with heroes, and you should be able to make an app that has fancy animation behaviour without explicitly defining animations paths all over the place, which IMO is much more in the spirit of flutter.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search