
Flutterでプラットフォームによって違うUIのダイアログを表示してみた。
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
大阪オフィスの山田です。家の中でよくねこを紛失しますが、大体布団の中にいます。今回は、プラットフォーム毎に、異なるUIのダイアログを表示してみます。
今回やること
前回作ったチャットアプリにサインイン機能を追加しましたので、今回はサインアウト機能をつけます。その際に表示する確認ダイアログをiOS、Androidで表示を変えてみたいと思います。
完成イメージ
iOS

Android

※画像はタブレット端末のスクリーンショットです
開発環境
flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, v0.5.1, on Mac OS X 10.13.5 17F77, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK 28.0.1)
[✓] iOS toolchain - develop for iOS devices (Xcode 9.4)
[✓] Android Studio (version 3.1)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[!] VS Code (version 1.26.1)
[✓] Connected devices (1 available)
flutter --version
Flutter 0.5.1 • channel beta • https://github.com/flutter/flutter.git Framework • revision c7ea3ca377 (3 months ago) • 2018-05-29 21:07:33 +0200 Engine • revision 1ed25ca7b7 Tools • Dart 2.0.0-dev.58.0.flutter-f981f09760
実装
前準備
前回作ったチャットアプリの続きから始めます。プラットフォーム毎に処理を切り替える実装自体は、前回からの続きからでなくても参考にできるかと思います。
実装
まずは、ナビゲーションバーの右上にSignOutボタンを表示する部分です。ログインしている時にのみボタンを表示するようにしています。実装は以下の通りです。
  import 'dart:io';
  import 'package:flutter/cupertino.dart';
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: new Text("Firebase Chat"),
        actions: _buildAppBarActionButton()
      ),
      body: Container(
          child: _user == null ? _buildGoogleSignInButton() : _buildChatArea()),
    );
  }
  List<Widget> _buildAppBarActionButton() {
    return _user == null ? null :
      <Widget>[
        MaterialButton(
          onPressed: () {
            StatelessWidget dialog;
            dialog = Platform.isIOS ? 
            _buildSignOutDialogiOS() 
            : _buildSignOutDialogAndroid();
            showDialog(
              context: context,
              builder: (context) {
                return dialog;
              }
            );
          },
          child: Text(
            "SignOut",
            style: TextStyle(
              fontSize: 14.0,
              color: Colors.white
            ),
          ),
        )
      ];
  }
dart:ioをimportして、Platform.isXXXメソッドでプラットフォームを判定します。_buildSignOutDialogXXXメソッドで各プラットフォームに対応したダイアログを生成します。ダイアログを生成するメソッドは以下の通りです。
  Widget _buildSignOutDialogAndroid() {
    return AlertDialog(
      title: Text("Confirm"),
      content: Text("Are you sure you want to Sign out?"),
      actions: <Widget>[
        FlatButton(
          child: const Text("Cancel"),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
        FlatButton(
          child: const Text("SignOut"),
          onPressed: () { 
            Navigator.pop(context);
            _signOut(); 
          },
        )
      ]
    );
  }
  Widget _buildSignOutDialogiOS() {
    return CupertinoAlertDialog(
      title: Text("Confirm"),
      content: Text("Are you sure you want to Sign out?"),
      actions: <Widget>[
        CupertinoDialogAction(
          child: const Text("Cancel"),
          isDefaultAction: true,
          onPressed: () {
            Navigator.pop(context);
          },
        ),
        CupertinoDialogAction(
          child: const Text("SignOut"),
          isDestructiveAction: true,
          onPressed: () { 
            Navigator.pop(context);
            _signOut(); 
          },
        )
      ]
    );
  }
  
  void _signOut() {
    _auth.signOut()
      .then((_) {
        setState(() {
          _user = null;
        });
      })
      .catchError((error) {
        print(error);
      });
  }
AndroidはAlertDialog, FlatButton、iOSはCupertinoAlertDialog, CuprtinoDialogActionクラスを使用しています。どちらも処理はほぼ同じでSignOutボタンがタップされたらサインアウトする処理を実行します。うーん、ここはほとんど処理が同じだし、なんとか共通化したいなぁ。。。今回、実装したソースはこちらに載せておきます。
最後に
いかがだったでしょうか。Flutterで完結する内容であれば、Flutterでプラットフォーム毎に処理を分けることができました。あんまり分けすぎるとFlutterを使うメリットも小さくなってしまうので、可能な限り統一して進めたい、というのが所感です。








