【Flutter】Material Theme Builder で好みの色をアプリに組み込む
はじめに
個人開発をするとき、いつもデザイン適用に悩みます。とくに配色。
デザインを知らないエンジニアでも、なんとかセンスのいい配色を適用してアプリをかっこよく見せたいものです。そんな中 Flutter でよく耳にする Material Design について色々調べていたところ、いい感じの色を選ぶだけですぐに Flutter アプリに適用できるサービスを見つけました。
本記事ではこちらのサービスを使い、直感的に選択した色を Flutter アプリに適用するまでを記した記事になります。
余談
つい先日に『センスは知識からはじまる』という書籍を読みました。
センスは感覚ではなく知識の集約だから、才能と決めつけず勉強しようねといった内容です。
勉強になる面白い本でした。
Material Design
Flutter を触っているとやたら Material Design という言葉を聞きますよね。
Material Design は 2014 年に Google が提唱したデザインシステムで、その名の通りマテリアル(=物質的)な、現実の物質の法則に則った直感的なデザインを表現しています。
そういった概念を Material Design のガイドライン に落とし込み、ガイドラインに準拠して用意された UI ブロックやその状態や伝達の仕組みを Material Components (MDC) というフレームワークとして提供しています。
MDC は Flutter にも提供されていて、AppBar
や BottomNavigationBar
、Drawer
などの Widget を実装するだけでオシャレな UI が実現できるのはこのためです。
Material Design や Material Design for Flutter はこのあたりが参考になると思います。
- Material Design(M3)
- Material Components widgets
- MDC-101 Flutter:Material Components (MDC) Basics(ハンズオン)
Material Design の Style には Icon や Elevation、Typography などさまざまな項目がありますが、今回は『Color』に着目しています。
Material Design の Color に関する説明はこちらです。
TL;DR
- Material Theme Builderで好きな配色を選ぶ。
- Export から「Flutter(Dart)」を選択する。
- ファイルを unzip し、
color_schemes.g.dart
とmain.g.dart
を lib 下にドラッグアンドドロップする。 -
main.g.dart
に倣ってmain.dart
を書き換える。
Material Design Builder for Flutter
テーマビルダーを適用するプロジェクトです。
デフォルトの counter app にコンポーネントを追加しただけです。
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
home: const MyHomePage(title: 'm3'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
double _currentSliderValue = 20;
bool _light = true;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
),
margin: const EdgeInsets.symmetric(horizontal: 40, vertical: 120),
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 64),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
const TextField(
obscureText: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
),
),
ElevatedButton(
onPressed: () {}, child: const Text('ElevatedButton')),
Slider(
value: _currentSliderValue,
max: 100,
divisions: 5,
label: _currentSliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
});
},
),
Switch(
value: _light,
activeColor: Colors.red,
onChanged: (bool value) {
setState(() {
_light = value;
});
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
bottomNavigationBar: NavigationBar(
destinations: const [
Icon(Icons.list),
Icon(Icons.home),
Icon(Icons.settings),
],
),
);
}
}
Material Theme Builder にアクセスし、『Custom』からサイドバーの Core colors の 4 色をピッカーから選択します。
Material Theme Builder
Core colors
Accent color 3 色と Neutral color 1 色を選びます。
色の役割のあれこれは こちら に書いてありますが、正直難しいです。これ理解して柔軟に扱えるデザイナーさんがいたらめっちゃ心強いですね。
Primary color
アプリの画面やコンポーネントで最も頻繁に表示される色です。
Secondary color
UI の中であまり目立たない部品に使われ、色の表現を広げます。
こちらはオプションで、テーマビルダーにおいても Primary color を選択すると自動で調整されます。
Tertiary color
Primary color と Secondary color のバランスをとったり、注目度を高めるためのアクセントとして用いたり。
自由に色を設定して製品の色彩表現の幅を広げることを目的としています。
Neutral color
面や背景に用いられ、テキストやアイコンを強調する色としても用いられる。
好みの色を選択する
色を選択し終えたら右上の『Export』から Flutter(Dart)をクリックし、zip をダウンロードし解凍します。
color_schemes.g.dart
とmain.g.dart
がフォルダに含まれているので、そのままプロジェクトの/lib
配下に移動します。
Flutter の他にも kotlin や CSS ファイルとしても出力できる
この時点でmain.g.dart
は動作するものとなっており、適用した色を確認することができます。今回はすでにmain.dart
を編集しているので、main.g.dart
の内容を真似て適用してあげます。
import 'package:flutter/material.dart';
+ import 'color_schemes.g.dart';
return MaterialApp(
+ theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme),
+ darkTheme: ThemeData(useMaterial3: true, colorScheme: darkColorScheme),
home: const MyHomePage(title: 'm3'),
);
また、color_schemes.g.dart
の ColorScheme class でエラーが出ているので該当箇所をコメントアウトします。
エラー箇所をコメントアウトする
エミュレータを再読み込みしてあげると、先程選択したテーマが反映されていると思います。
一気に counter app のデフォルト感がなくなりましたね。
また、useMaterial3: true
というように Material Design 3(Material Design の最新版)を適用しているので、ボタンの形状やAppBar
の色使いなどが若干変わっています。
ダークモード
color_schemes.g.dart
の記述でお気づきかもしれませんが、ダークモード用の配色も用意されています。
darkColorScheme
const darkColorScheme = ColorScheme(
brightness: Brightness.dark,
primary: Color(0xFFFFB2B9),
onPrimary: Color(0xFF67001F),
primaryContainer: Color(0xFF91002F),
onPrimaryContainer: Color(0xFFFFDADC),
secondary: Color(0xFFE5BDBF),
onSecondary: Color(0xFF43292C),
secondaryContainer: Color(0xFF5C3F42),
onSecondaryContainer: Color(0xFFFFDADC),
tertiary: Color(0xFFE8C08E),
onTertiary: Color(0xFF442B06),
tertiaryContainer: Color(0xFF5D411B),
onTertiaryContainer: Color(0xFFFFDDB6),
error: Color(0xFFFFB4AB),
errorContainer: Color(0xFF93000A),
onError: Color(0xFF690005),
onErrorContainer: Color(0xFFFFDAD6),
background: Color(0xFF201A1A),
onBackground: Color(0xFFECE0E0),
surface: Color(0xFF201A1A),
onSurface: Color(0xFFECE0E0),
surfaceVariant: Color(0xFF524344),
onSurfaceVariant: Color(0xFFD7C1C2),
outline: Color(0xFF9F8C8D),
onInverseSurface: Color(0xFF201A1A),
inverseSurface: Color(0xFFECE0E0),
inversePrimary: Color(0xFFB61E44),
shadow: Color(0xFF000000),
surfaceTint: Color(0xFFFFB2B9),
// outlineVariant: Color(0xFF524344),
// scrim: Color(0xFF000000),
);
ThemeData
で読み込むカラースキームをダークモードの配色にします。
return MaterialApp(
- theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme),
+ theme: ThemeData(useMaterial3: true, colorScheme: darkColorScheme),
home: const MyHomePage(title: 'm3'),
);
ダークモードの適用
これだけでダークモード実装の工数がかなり省けますね。
適用する色のロールの変更もかんたんです。
例えば FloatingActionButton の色を アクセントカラーにしたいときは、以下のようにテーマを定義している直近の先祖(この場合 MyApp の MaterialApp)のテーマデータを取得し、その中のtertiaryContainer
の色を適用してあげます。
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
+ backgroundColor: Theme.of(context).colorScheme.tertiaryContainer,
child: const Icon(Icons.add),
),
FAB の色を変更
おわりに
はじめてアドベントカレンダーに参加してみましたが、同じ技術を扱う開発者の方との一体感を感じられる良いイベントですね。
Flutter を触り始めてから半年ほど経ちますが、個人開発やコミュニティ(主に Twitter)の盛り上がり、多くのイベント開催など触れていて本当に楽しい技術です。来年はもっとコミュニティの発展や個人開発に力を入れたいなぁ。
zenn 記事もまだまだ書いていく予定ですので、今後もよろしくお願いします。
よいクリスマス、よいお年を!
Discussion