【Flutter】settings_uiを試す
概要
settings_ui パッケージを使用してアプリの設定画面を実装する方法を色々試してみたいと思います。
動作環境
- macOS Monterey バージョン12.6 Apple M1
- Flutter SDK バージョン 3.3.8
- iOS シュミレータ iPhone 14 Pro iOS 16.0
- Android シュミレータ Pixel 4 API 32
パッケージインストール
dependencies:
settings_ui: ^2.0.2
最小限の構成で実装してみる
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:settings_ui/settings_ui.dart';
class SettingsPage extends HookConsumerWidget {
const SettingsPage({Key? key}) : super(key: key);
Widget build(BuildContext context, WidgetRef ref) {
return SettingsList(
sections: [
SettingsSection(
title: const Text('セクション'),
tiles: <SettingsTile>[
SettingsTile.navigation(
leading: const Icon(Icons.language),
title: const Text('Language'),
value: const Text('日本語'),
),
],
),
],
);
}
}
↑の実装をAndroid/iOSそれぞれで実行すると結果は以下になります。
Android | iOS |
---|---|
基本的な構成としては
- SettingsList
-
sections
に複数のAbstractSettingsSection
を持つ
-
- SettingsSection
-
tiles
に複数のAbstractSettingsTile
を持つ - カスタム実装用に
CustomSettingsSection
が存在する
-
- SettingsTile
- カスタム実装用に
CustomSettingsTile
が存在する
- カスタム実装用に
↑の3つを使用して設定画面を構築していきます。
各Widget
SettingsList
sections
パラメータに AbstractSettingsSection
一覧を設定します。また他指定できるパラメータで気になったものを以下に特筆してます。
DevicePlatform platform パラメータ
デフォルトだとOS毎の見た目にしてくれるみたいですが、このパラメータを設定しておくと好きなOSの見た目に固定できます。
先ほど↑の実装を platform = iOS
に固定してみたいと思います。
class SettingsPage extends HookConsumerWidget {
const SettingsPage({Key? key}) : super(key: key);
Widget build(BuildContext context, WidgetRef ref) {
return SettingsList(
platform: DevicePlatform.iOS, // ← 追加
sections: [
...
],
),
],
);
}
}
↓ AndroidもiOSと同じ見た目になりました。
(どちらも platform: DevicePlatform.iOS
で実行してます)
Android | iOS |
---|---|
全platformの値で試してみた結果以下の様になりました。※ 試した端末はiOSシュミレータです。
platform | スクリーンショット |
---|---|
DevicePlatform.android | |
DevicePlatform.fuchsia | |
DevicePlatform.iOS | |
DevicePlatform.linux | |
DevicePlatform.macOS | |
DevicePlatform.windows | |
DevicePlatform.web |
ApplicationType applicationType パラメータ
material
と cupertino
と both
を指定できます。
ドキュメントだけだとあんまり詳細が分かりませんでしたが、実装を見る限り brightness
の参照元を決めるのに使われているみたいです。
Brightness calculateBrightness(BuildContext context) {
final materialBrightness = Theme.of(context).brightness;
final cupertinoBrightness = CupertinoTheme.of(context).brightness ??
MediaQuery.of(context).platformBrightness;
switch (applicationType) {
case ApplicationType.material:
return materialBrightness;
case ApplicationType.cupertino:
return cupertinoBrightness;
case ApplicationType.both:
return platform != DevicePlatform.iOS
? materialBrightness
: cupertinoBrightness;
}
}
SettingsSection
tiles
パラメータに AbstractSettingsTile
一覧を設定します。
他指定できるパラメータとして
- title (Widget)
- margin (EdgeInsetsDirectional)
を指定できます。
SettingsTile
実際の設定項目を定義します。必須パラメータは title
のみになっています。
また SettingsTile には以下の Named constructors が用意されています。
- SettingsTile.navigation
- SettingsTile.switchTile
↑に関しては後述しています。まずは通常のコンストラクタで作成した場合を見ていきます。
titleのみ設定
まずは単純に title
のみ設定した場合を試してみます。
return SettingsList(
platform: DevicePlatform.iOS,
sections: [
SettingsSection(
title: const Text('セクション'),
tiles: <SettingsTile>[SettingsTile(title: const Text('タイトル'))],
),
],
);
↑の実行結果は以下の様になります。
leading
と trailing
を設定
次に、ListTile と同じ様に Widget leading
と Widget trailing
を設定できるのでそちらも試してみます。
return SettingsList(
platform: DevicePlatform.iOS,
sections: [
SettingsSection(
title: const Text('セクション'),
tiles: <SettingsTile>[
SettingsTile(
leading: const FlutterLogo(), // ← 追加
title: const Text('タイトル'),
trailing: const Icon(Icons.more_vert), // ← 追加
),
],
),
],
);
↑の実行結果としては以下の様になります。
description
と value
補足文を表示させる description
や、設定値を表示させる value
を設定できます。Plarform
や SettingsTile.navigation
で表示させた場合で挙動が違ってきます。
以下の実装で Plarform
や Named constructors
を使用した際の表示をまとめてみました。
また、trailing
を指定すると value
が表示されないので削除してます。
SettingsTile(
leading: const FlutterLogo(),
title: const Text('タイトル'),
description: const Text('description'),
value: const Text('value'),
)
Platform | コンストラクタ | 表示結果 |
---|---|---|
DevicePlatform.iOS | 通常 | |
DevicePlatform.android | 通常 | |
DevicePlatform.web | 通常 | |
DevicePlatform.iOS | SettingsTile.navigation | |
DevicePlatform.android | SettingsTile.navigation | |
DevicePlatform.web | SettingsTile.navigation |
※ Platformに関しては iOS ( macOS / windows も同じ), android (fuchsia / linux も同じ), web で比較してます。
SettingsTile.switchTile
ON/OFF の設定項目を作成する際に使用します。
以下の実装で、各 Platform 毎の表示の違いを以下にまとめてみました。
SettingsTile.switchTile(
leading: const FlutterLogo(),
title: const Text('タイトル'),
description: const Text('description'),
initialValue: true,
onToggle: (value) {},
)
Platform | 表示結果 |
---|---|
DevicePlatform.iOS | |
DevicePlatform.android | |
DevicePlatform.web |
※ Platformに関しては iOS ( macOS / windows も同じ), android (fuchsia / linux も同じ), web で比較してます。
その他: package_info_plusを使用してアプリのバージョン表示
package_info_plusパッケージを使用して、設定画面によくあるアプリのバージョンを表示してみたいと思います。
パッケージインストール
dependencies:
package_info_plus: ^3.0.2
実装例
class SettingsPage extends HookConsumerWidget {
const SettingsPage({Key? key}) : super(key: key);
Widget build(BuildContext context, WidgetRef ref) {
final fromPlatform = useMemoized(PackageInfo.fromPlatform);
final snapshot = useFuture(fromPlatform);
if (!snapshot.hasData) {
return const SizedBox.shrink();
}
return SettingsList(
platform: DevicePlatform.iOS,
sections: [
SettingsSection(
title: const Text('セクション'),
tiles: <SettingsTile>[
SettingsTile(
leading: const Icon(Icons.info),
title: const Text('アプリのバージョン'),
value: Text("${snapshot.data?.version}"))
],
),
],
);
}
}
実行結果は↓の様に表示されます。
その他: 「お問い合わせ」項目を追加し、タップするとメーラーが立ち上がる様にする
url_launcherを使用して項目をタップするとメーラーが起動するようにしてみます。
パッケージインストール
dependencies:
url_launcher: ^6.1.7
事前準備
-
Android
-
AndroidManifest.xml
に以下を追加しておく<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.xxxx"> <application android:label="@string/app_name" android:name="${applicationName}" android:icon="@mipmap/ic_launcher"> ... </application> <!-- 以下を追加 --> <queries> <intent> <action android:name="android.intent.action.VIEW" /> <data android:scheme="mailto" /> </intent> </queries> </manifest>
-
-
iOS
-
Info.plist
に以下を追加しておく<key>LSApplicationQueriesSchemes</key> <array> <string>mailto</string> </array>
-
実装例
class SettingsPage extends HookConsumerWidget {
const SettingsPage({Key? key}) : super(key: key);
Widget build(BuildContext context, WidgetRef ref) {
return SettingsList(
platform: DevicePlatform.iOS,
sections: [
SettingsSection(
title: const Text('サポート'),
tiles: <SettingsTile>[
SettingsTile.navigation(
leading: const Icon(Icons.mail),
title: const Text('お問い合わせ'),
onPressed: (context) => _launchMailer(),
),
],
),
],
);
}
String? _encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((MapEntry<String, String> e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
Future<void> _launchMailer() async {
const address = 'メールアドレス';
final Uri uri = Uri(
scheme: 'mailto',
path: address,
query: _encodeQueryParameters(<String, String>{
'subject': 'メールの件名',
}),
);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
// エラー処理
}
}
}
動作イメージとしては以下の様になります。
Discussion