SwipeablePageRoute | Swipeable Pages to Navigate Back with Futter

Swipe to navigate back and admire beautifully morphing widgets.

swipeable_page_route demo

SwipeablePageRoute

SwipeablePageRoute is a specialized CupertinoPageRoute that allows your users to go back by swiping anywhere on the current page. Use it instead of MaterialPageRoute or CupertinoPageRoute:

Navigator.of(context).push(SwipeablePageRoute(
  builder: (BuildContext context) => MyPageContent(),
));

If your page contains horizontally scrollable content, you can limit SwipeablePageRoute to only react on drags from the start (left in LTR, right in RTL) screen edgeโ€‰โ€”โ€‰just like CupertinoPageRoute:

Navigator.of(context).push(SwipeablePageRoute(
  onlySwipeFromEdge: true,
  builder: (BuildContext context) => MyHorizontallyScrollablePageContent(),
));

You can get the SwipeablePageRoute wrapping your current page using context.getSwipeablePageRoute<T>().

MorphingAppBar & MorphingSliverAppBar

As you can see in the demo above, there's a beautiful animation happening to the AppBar. That's a MorphingAppBar!

You can construct MorphingAppBar (corresponds to AppBar) and MorphingSliverAppBar (corresponds to SliverAppBar) just like the originals:

MorphingAppBar(
  backgroundColor: Colors.green,
  title: Text('My Page'),
  actions: <Widget>[
    IconButton(
      key: ValueKey('play'),
      icon: Icon(Icons.play_arrow),
      onPressed: () {},
    ),
    IconButton(
      key: ValueKey('favorite'),
      icon: Icon(Icons.favorite),
      onPressed: () {},
    ),
    PopupMenuButton<void>(
      key: ValueKey('overflow'),
      itemBuilder: (context) {
        return [
          PopupMenuItem<void>(child: Text('Overflow action 1')),
          PopupMenuItem<void>(child: Text('Overflow action 2')),
        ];
      },
    ),
  ],
  bottom: TabBar(
    tabs: <Widget>[
      Tab(text: 'Tab 1'),
      Tab(text: 'Tab 2'),
      Tab(text: 'Tab 3'),
    ],
  ),
)

Both MorphingAppBars internally use Heros, so if you're not navigating directly inside a MaterialApp, you have to add a HeroController to your Navigator:

Navigator(
  observers: [HeroController()],
  onGenerateRoute: // ...
)

To animate additions, removals, and constants in your AppBars actions, we compare them using Widget.canUpdate(Widget old, Widget new). It compares Widgets based on their type and key, so it's recommended to give every action Widget a key (that you reuse across pages) for correct animations.

 

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add swipeable_page_route

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):


dependencies:
  swipeable_page_route: ^0.2.3

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:swipeable_page_route/swipeable_page_route.dart';

example/lib/main.dart

import 'package:black_hole_flutter/black_hole_flutter.dart';
import 'package:flutter/material.dart';
import 'package:swipeable_page_route/swipeable_page_route.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '๐Ÿ”™ swipeable_page_route example',
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: MorphingAppBar(
        title: Text('๐Ÿ”™ swipeable_page_route example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.navigator
                .push<void>(SwipeablePageRoute(builder: (_) => SecondPage()));
          },
          child: Text('Open page 2'),
        ),
      ),
    );
  }
}

class SecondPage extends StatefulWidget {
  @override
  _SecondPageState createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
  @override
  Widget build(BuildContext context) {
    // Gets the `SwipeablePageRoute` wrapping the current page.
    final pageRoute = context.getSwipeablePageRoute<void>()!;

    return Scaffold(
      appBar: MorphingAppBar(
        title: Text('Page 2'),
        actions: <Widget>[
          IconButton(
            key: ValueKey('check'),
            icon: Icon(Icons.check),
            onPressed: () {},
          ),
          IconButton(
            key: ValueKey('star'),
            icon: Icon(Icons.star),
            onPressed: () {},
          ),
          IconButton(
            key: ValueKey('play_arrow'),
            icon: Icon(Icons.play_arrow),
            onPressed: () {},
          ),
          PopupMenuButton<void>(
            itemBuilder: (context) => [
              PopupMenuItem(child: Text('One')),
              PopupMenuItem(child: Text('Two')),
            ],
          ),
        ],
      ),
      body: SizedBox.expand(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Can swipe: ${pageRoute.canSwipe}'),
            TextButton(
              onPressed: () {
                // You can disable swiping completely using `canSwipe`:
                setState(() => pageRoute.canSwipe = !pageRoute.canSwipe);
              },
              child: Text('Toggle'),
            ),
            SizedBox(height: 32),
            ElevatedButton(
              onPressed: () {
                context.navigator.push<void>(SwipeablePageRoute(
                  // This option has to be enabled for pages with horizontally
                  // scrollable content, as otherwise, `SwipeablePageRoute`'s
                  // swipe-gesture intercepts those gestures in the page. This way,
                  // only swipes starting from the left (LTR) or right (RTL) screen
                  // edge can be used to navigate back.
                  canOnlySwipeFromEdge: true,
                  // You can customize the width of the detection area with
                  // `backGestureDetectionWidth`.
                  builder: (_) => ThirdPage(),
                ));
              },
              child: Text('Open page 3'),
            ),
          ],
        ),
      ),
    );
  }
}

class ThirdPage extends StatefulWidget {
  @override
  _ThirdPageState createState() => _ThirdPageState();
}

class _ThirdPageState extends State<ThirdPage>
    with SingleTickerProviderStateMixin {
  static const _tabCount = 3;
  late final TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: _tabCount, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: MorphingAppBar(
        backgroundColor: Colors.green,
        title: Text('Page 3'),
        actions: <Widget>[
          IconButton(
            key: ValueKey('star'),
            icon: Icon(Icons.star),
            onPressed: () {},
          ),
          IconButton(
            key: ValueKey('play_arrow'),
            icon: Icon(Icons.play_arrow),
            onPressed: () {},
          ),
          IconButton(
            key: ValueKey('favorite'),
            icon: Icon(Icons.favorite),
            onPressed: () {},
          ),
          PopupMenuButton<void>(
            itemBuilder: (context) => [
              PopupMenuItem(child: Text('One')),
              PopupMenuItem(child: Text('Two')),
            ],
          ),
        ],
        bottom: TabBar(
          controller: _tabController,
          indicatorColor: Colors.white,
          isScrollable: true,
          tabs: <Widget>[
            for (var i = 0; i < _tabCount; i++) Tab(text: 'Tab ${i + 1}'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          for (var i = 0; i < _tabCount; i++)
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('This is tab ${i + 1}'),
                ElevatedButton(
                  onPressed: () {
                    context.navigator.push<void>(
                      SwipeablePageRoute(builder: (_) => SecondPage()),
                    );
                  },
                  child: Text('Open page 2'),
                ),
              ],
            ),
        ],
      ),
    );
  }
}

Download Details: 
 

Author: JonasWanke

Official Website: https://github.com/JonasWanke/swipeable_page_route 

21.10 GEEK