5

I want to have the top half of by screen appear static when navigating between pages in Flutter.

To try to make this happen I put use the Hero widget and use it on a column that contains an AppBar and some other content that I want to appear static when pushing a new page.

The App Bar itself remains static but the back arrow disappears when the animation starts and reappears when the animation is done.

How can I have the back arrow remain visible the entire time while the rest of the page is animating into place?

 class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Hero(
            tag: 'top',
            child: Column(
              children: <Widget>[
                AppBar(
                  title: Text('First'),
                  backgroundColor: Color.fromARGB(255, 50, 64, 182),
                ),
                Container(
                  height: 80.0,
                )
              ],
            ),
          ),
          RaisedButton(
            child: Text('Next'),
            onPressed: () {
              Navigator.pushNamed(context, '/second');
            },
          ),
        ],
      ),
    );
  }
}

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Hero(
            tag: 'top',
            child: Column(
              children: <Widget>[
                AppBar(
                  title: Text('Second'),
                ),
                Container(
                  height: 80.0,
                  // color: Colors.green,
                ),
              ],
            ),
          ),
          RaisedButton(
            child: Text('Back'),
            onPressed: () {
              Navigator.pop(context);
            },
          ),
        ],
      ),
    );
  }
}
blackpool
  • 485
  • 2
  • 8
  • 16

3 Answers3

1

Things weren't quite set up right in your code. It should go Scaffold/Hero/your content. I've also used this simple fading page route when performing the navigation:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text('First'),
          leading: Icon(null),
          backgroundColor: Color.fromARGB(255, 50, 64, 182)),
      body: Hero(
        tag: 'top',
        child: Column(
          children: <Widget>[
            Container(height: 80.0),
            RaisedButton(
              child: Text('Next'),
              onPressed: () {
                Navigator.push(context, MyCustomRoute(builder: (context) {
                  return SecondScreen();
                }));
              },
            ),
          ],
        ),
      ),
    );
  }
}

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text('Second'),
          leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () {
            Navigator.pop(context);
          },),
          backgroundColor: Color.fromARGB(255, 50, 64, 182)),
      body: Hero(
        tag: 'top',
        child: Column(
          children: <Widget>[
            Container(height: 80.0),
            RaisedButton(
              child: Text('Back'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),
    );
  }
}

class MyCustomRoute<T> extends MaterialPageRoute<T> {
  MyCustomRoute({ WidgetBuilder builder, RouteSettings settings })
      : super(builder: builder, settings: settings);

  @override
  Widget buildTransitions(BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
      Widget child) {
    if (settings.isInitialRoute)
      return child;
    // Fades between routes. (If you don't want any animation, 
    // just return child.)
    return new FadeTransition(opacity: animation, child: child);
  }
}

Demo gif

soupjake
  • 3,293
  • 3
  • 17
  • 32
  • But this does not do what I want. I want the app bar to not flicker and the backarrow when you navigate to one more screen to always be visible and not disappear and reappear. So the only visible change when pushing and popping should be the text changing on the app bar – blackpool Nov 29 '18 at 15:19
  • Sorry I didn't quite get that's what you wanted. I've edited my answer to hopefully be what you want. Let me know what you think. – soupjake Nov 29 '18 at 15:54
  • How would it look if you pushed one more on the stack. Would the arrow remain stationary during the animation? – blackpool Nov 29 '18 at 16:33
  • The example I've shown will work with additional pages and stacks if each one apart from the main one is like the second page in the code I've provided. Give it a try! – soupjake Nov 29 '18 at 18:59
  • Thanks for your effort but at least on IOS the content of the App Bar is not stationary. I can clearly see the arrow being replaced and the text on the app bar sliding out to be replaced with another. The original code I posted had the title stationary but has the issue with the arrow being visibly replaced. – blackpool Nov 29 '18 at 20:08
  • Yeah mine has a fade animation. Would you not want that? Transitions in apps should have some sort of animation to signal change to the user. – soupjake Nov 29 '18 at 20:16
  • If I just return child from the buildTransitions methods instead of the FadeTransition it will actually work with the App Bar but then I also loose the sliding animation on the rest of the page that is not part of the Hero widget. – blackpool Nov 29 '18 at 20:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/184493/discussion-between-blackpool-and-snakeyhips). – blackpool Nov 29 '18 at 21:03
0

You could do automaticallyImplyLeading: false and then do

leading: IconButton(
        icon: Icon(Icons.arrow_back),
        onPressed: () => Navigator.of(context).pop(),
),
leodriesch
  • 5,308
  • 5
  • 30
  • 52
0

I have it done this way, by adding automaticallyImplyLeading: true,

Hope this solves your problem!

  appBar: AppBar(
    automaticallyImplyLeading: true,
    ),
Margriet
  • 197
  • 2
  • 10