skip to Main Content

I’m working on an app that can display a "no connection" widget at the top of it when internet is lost. Since my app doesn’t have a "forehead" part per-se, I’m just adding a widget to the tree (to be more precise, I make an appBar appear).

The problem with that solution is that even with the use of ShowUpAnimation, when the widget appears, the space is taken instantly. This displaces all the elements brutally, it looks pretty choppy and bad. Here’s what it looks like, pardon my literal french:

bad looking pop-in

I’m looking for a solution to this problem that would allow me to ease-in that widget with a transition that pushes the rest of the screen down gently over a certain duration so it looks smoother. Additionally, my current solution doesn’t handle widget exit, it just disappears which is even more jarring.

Thanks in advance !

Code:

How the app bar is called in the Scaffold:

appBar: !viewModel.hasConnection
              ? const PreferredSize(
                  preferredSize: Size.fromHeight(35),
                  child: NoConnectionAppBar(),
                ) : null

viewModel.hasConnection is automatically updated with a Stream.

How the app bar is implemented in the class:

Widget build(BuildContext context) {
    return ShowUpAnimation(
        curve: Curves.linear,
        offset: -0.5,
        child: AppBar(...)
     );
}

3

Answers


  1. Chosen as BEST ANSWER

    Here is my answer, there were two cases:

    In the first case, the bar needed to take some vertical space on the screen. So I removed the appBar, and instead wrapped the Scaffold in an Expanded and then in Column. In the controller, I defined a variable named topBarWidget. When the controller gets created, we initialized that widget to either my no connection bar or to a 0 height SizedBox. We also hook up this logic to the function that handles connection detection. Finally, I added an AnimatedSize widget on top of the Column with that topBarWidget as the child. Works great, make sure the Column is wrapped in a safe area though.

    In the second case, I actually found I didn't need my widget to take vertical space, so I just added the same logic in the controller to define a topBarWidget. Then, I wrapped that topBarWidget in an AnimatedSwitcher with a transition builder that used a SizeTransition.

    You will find the code the result. Thanks @dstreissi for putting me on the right tracks.

    look how smooth it is

    1 - Taking up vertical space

    SafeArea(
        child: Column(
            children: [
                AnimatedSize(
                    duration: const Duration(milliseconds: 800),
                    curve: Curves.easeIn,
                    child: viewModel.topBarWidget,
                ),
                Expanded(
                    child: Scaffold(...),
                ),...,
    );
    

    2 - Stacking up on the Z-axis

    SafeArea(
                child: Scaffold(
                  ...
                  body: Stack(
                    children: [
                      SingleChildScrollView(
                        child: Column(
                          children: [...],
                        ),
                      ),
                      AnimatedSwitcher(
                        duration: const Duration(milliseconds: 800),
                        transitionBuilder: (Widget child,
                        Animation<double> animation) => SizeTransition(sizeFactor: animation, child: child,),
                        child: viewModel.topBarWidget,
                      ),
                    ],
                  ),
                ),
              );
    

    Notice how I put the ScrollView inside the Stack so that my noConnection message would stay on top of the screen even when scrolling down.


  2. If you want to stick with the AppBar you should consider using something like SliverAppBar it has the expandedHeight property where you can set its height and change it on event.
    Keep in mind that SliverAppBar should be put inside scrollview with slivers property. For example — CustomScrollView

    More information about:
    SliverAppBar (official)
    CustomScrollView (official)
    unofficial guide which you might find helpful

    Login or Signup to reply.
  3. You can also use an AnimatedContainer instead the AppBar and place it above all other Widgets. This gives the advantage that the height can be animated, so the other Widgets are sliding down with the space the AnimatedContainer uses.

    more information see here: AnimatedContainer

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