2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Flutter】AndroidでiOS風の画面遷移とスワイプによるバックを実現する

Posted at

はじめに

Flutterはクロスプラットフォームなフレームワークですが、Flutterでモバイルアプリを開発していて、Android・iOSという二つのOSで画面遷移時の処理を統一するのに少し工夫が必要だったため共有します。
本記事ではAndroidにおいてiOS風の画面がスライドするようなトランジションエフェクトと、スワイプによる画面バック処理の実装について紹介します。
Androidバックキー押下時に何か処理を実装していた場合、そのままではスワイプによる画面バック動作が無効になってしまうので、その解決を試みました。

目標

AndroidでiOS風のトランジションと「スワイプで前の画面に戻る」動作を共通で実装させる。

実装

実装の内容は大まかに以下となります。

1. AndroidでiOS風の画面遷移をさせる
2. バックキーに処理を設定する
3. バックキー押下時の処理とスワイプによるバック動作を併存させる

1.AndroidでiOS風の画面遷移をさせる

Flutterのコードを読むと、以下のようにOSによって異なる画面遷移テーマが設定されていることがわかります。

PageTransitionsTheme
static const Map<TargetPlatform, PageTransitionsBuilder> _defaultBuilders = <TargetPlatform, PageTransitionsBuilder>{
  TargetPlatform.android: ZoomPageTransitionsBuilder(),
  TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
  TargetPlatform.macOS: CupertinoPageTransitionsBuilder(),
};

ここから、AndroidでiOS風の画面遷移を実現するためには、Androidに対してもiOSと同様のテーマであるCupertinoPageTransitionsBuilderをすれば良いとわかります。
よってMaterialAppのbuildThema内で、たとえば次のように実装します。

sampleコード
//main.dart内を抜粋
return MaterialApp(
 theme: ThemeData(
 pageTransitionsTheme: const PageTransitionsTheme(
   builders: <TargetPlatform, PageTransitionsBuilder>{
     TargetPlatform.android: CupertinoPageTransitionsBuilder(),//Androidの遷移もIOS風に指定している
     TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
   },
 ),
 title: 'SAMPLE',
 locale: localeJP,
);

これでAndroidでiOSと同じ画面遷移を行うことができました。
続いてAndroidにおけるバックキーの動作を実装していきましょう。

2. バックキーに処理を設定する

今回、Androidのバックキーを押したときに特定の処理を実行させたかったのでこちらを実装していきます。

デフォルトではバックキーを押下したとき画面をバックする動作が実行されるだけなので、任意の処理を実行させるため、WillPopScopeというウィジェットを使用します。

WillPopScopeはchildプロパティに指定したウィジェットに対して、画面が戻る動きを検知して、そのタイミングで実行されるコールバックを設定できるウィジェットになります。
(正確には画面が破棄されることを拒否するコールバックを登録できると公式のドキュメントに説明されています

次のようにWillPopScopeでウィジェットをラップすることで、Androidのバックキー押下時に実行されるコールバック処理を登録することができます。

sampleコード
WillPopScope(
  onWillPop: () async { //コールバックはFuture<bool>で設定する
    /*
      バックキー押下時に実行させたい処理
    */
    return true; //trueなら処理実行後画面を閉じる
  },
  child: Scaffold(
    body: //画面を構成するWidget
  ),
)

WillPopScopeは画面をバックさせたくないときにも使用できますが、今回はAndroidのバックキー押下時の処理を設定するために利用します。

3. バックキー押下時の処理とスワイプによるバック動作を併存させる

ここまででAndroidにおけるiOS風の画面処理と、バックキー押下時に実行される処理の設定を行いました。
この状態では、実はスワイプによる画面バック機能が無効になっています。
その理由はFlutterにおける画面遷移の基礎となっているModalRouteクラスにあります。

Flutterのソースコード上を見ていくとModalRouteクラスにhasScopedWillPopCallbackというgetterが存在することがわかります。

こちらのコメントを読むと、

This method is used to disable the horizontal swipe pop gesture supported
by [MaterialPageRoute] for [TargetPlatform.iOS] and
disabled.

とあり、WillPopScopeCallbackが複数個あるとき、スワイプでバックするジェスチャが非活性化されていることがわかります。

ここで、Flutterにおける最もシンプルな画面遷移処理の例を次に示します。

シンプルな画面遷移処理
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()),
);

このMaterialPageRouteクラスは、先ほど言及したModalRouteクラスを継承しているため、MaterialPageRouteのサブクラスを作ればhasScopedWillPopCallbackをオーバーライドすることができます。

したがって、スワイプによるバック動作の非活性化を防ぐためには次のようにカスタムしたクラスを定義し、使用します。

CustomMaterialPageRoute
class CustomMaterialPageRoute extends MaterialPageRoute {
  CustomMaterialPageRoute(
    {
      required WidgetBuilder builder,
      required RouteSettings settings,
    }): super(builder: builder, settings: settings);

  @override
  bool get hasScopedWillPopCallback => false; //WillPopScopeがあるときもスワイプによるバックを許容する
}

MaterialApp内での使用例を次に示します。

sampleコード
return MaterialApp(
  theme: ThemeData(
    pageTransitionsTheme: const PageTransitionsTheme(
      builders: <TargetPlatform, PageTransitionsBuilder>{
        TargetPlatform.android: CupertinoPageTransitionsBuilder(),//Androidの遷移もIOS風に指定している
        TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
      },
  ),
  title: 'SAMPLE',
  locale: localeJP,
  onGenerateRoute: (RouteSettings settings) {
    swich(settings.name){
      case: '/SecondPage'{
        return CustomMaterialPageRoute(
          builder: ((context) => SecondPage()),
          settings: settings,
        );
      }
      //以下ルート名別に処理を設定する        
    },
  );
);

これでWillPopScopeで設定したコールバックとスワイプによる画面バック動作を併存させることができました。

おわりに

今回はFlutterで

  • Android上でもiOS風の画面遷移を実現する
  • スワイプによる画面バック動作を保持したままバックキー押下時に処理を設定する
    という二つの処理についてご紹介しました。
    閲覧ありがとうございました。
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?