First_Strike
First_Strike

Reputation: 1089

Flutter - What's the best practice to create a fixed AppBar during navigation

In native android development, it is common to use FragmentTransaction to create a navigation animation, where the actionBar's position stays fixed (but actionBar's content changed), and the fragment beneath actionBar performs a transition animation (like slide in or out).

To put it simple, the AppBar and the body performs different transition animation. In flutter, what is the best practice to create such animation?

Currently I can think of a solution of using a navigation in Scaffold.body and using Stream + StreamBuilder to start AppBar redraw. Something like the following code.

Scaffold(
    appBar: StreamBuilder<Int>(
        stream: Bloc.of(context).currentFragmentId
        builder: //Some logic to decide which AppBar is appropriate
    ),
    body: Navigator(
        //Navigation between fragments
    ),
)

But this is really weird. So is there a best practice to do this? Please let me know!

Upvotes: 4

Views: 2949

Answers (2)

Flawn
Flawn

Reputation: 61

Maybe a more elegant solution (code-wise) as opposed to @First_Strike:

import 'package:flutter/material.dart';

extension HeroAppBar on AppBar {
  PreferredSizeWidget toHero(Object tag) {
    return PreferredSize(
      preferredSize: preferredSize,
      child: Hero(tag: tag, child: this),
    );
  }
}

Upvotes: 0

First_Strike
First_Strike

Reputation: 1089

Well, since there is currently no answer availble. I'm going to share my solution here, though it is not so elegant.

The solution is to wrap AppBar in a Hero widget. Since Scaffold only takes a PreferedSize widget as an appbar, some customization is required.

class HeroAppBar extends StatelessWidget implements PreferredSizeWidget {
//...
  @override
  final Size preferredSize = Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0));
//...
  @override
  Widget build(BuildContext context) {
    return Hero(
      tag: tag,
      child: AppBar(
        //...
      ),
    );
  }
}

And make sure your Navigator implemented the HeroController. (Default Navigator has already implemented it)

Upvotes: 1

Related Questions