FlutterのThemeを理解する

この記事はFlutter 全部俺 Advent Calendar 12日目の記事です。

このアドベントカレンダーについて

このアドベントカレンダーは @itome が全て書いています。

基本的にFlutterの公式ドキュメントとソースコードを参照しながら書いていきます。誤植や編集依頼はTwitterにお願いします。

FlutterのThemeとはなにか

Flutterは、アプリに統一的なデザインスタイルを提供するために、Themeクラスを提供しています。 Themeを適切に使えば、最小限のコストでアプリのデザインを変更したり、ダークモードに対応したりできます。

Theme の基本的な使い方

Themeは基本的にMaterialAppとのセットで使います。MaterialApptheme: に指定したThemeDataが アプリ全体に適用されます。

...
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        ...
      ),
      home: Scaffold(
...

テーマを各Widgetに適用させたい時は、Theme.of(context)で取得したThemeDataからスタイルを取り出して使います。 (Theme.of(context)で共通のThemeDataが取得できる仕組みに関しては 6日目の記事参照)

...
     Text(
       'Hello',
       style: Theme.of(context).textTheme.body1,
     ),
...

基本的にはこれだけです。

Themeを切り替える

Themeの切り替えは通常の状態変更と同様にMaterialAppに渡すThemeDataを切り替えるだけでできます。 MaterialAppは内部でAnimatedThemeを使っているので、Themeの切り替え時に自動的にアニメーションも入れてくれます。

TextAppBarなどの多くのWidgetは色のデフォルト値をTheme.of(context)から取得して指定しているので、 Themeを切り替えるだけでそれに合わせてWidgetの色が変わります

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  bool dark = false;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: dark ? ThemeData.dark() : ThemeData.light(),
      home: Scaffold(
        appBar: AppBar(title: Text('Toggle theme sample')),
        body: Center(
          child: RaisedButton(
            onPressed: () {
              setState(() => dark = !dark);
            },
            child: Text('Toggle theme'),
          ),
        ),
      ),
    );
  }
}
Themeを切り替える

OSのダークモードに対応する

Andorid/iOSともに最新のOSではダークモードに対応していますが、 FlutterではThemeを使って簡単にダークテーマに対応することができます。

MaterialApptheme: に加えてdarkTheme: を追加するだけです。

...
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      home: Scaffold(
...
OSのダークモードを切り替える

Theme で設定できるプロパティ一覧

かなりたくさんあるので、全て手づから設定するのは現実的ではないです。 基本的にデフォルトのTheme.light()もしくはTheme.dark()をつかい、 デザインに合わせて必要なところだけ変更する運用にするのが最適だと思います。

プロパティ 説明
brightness アプリの全体の明るさ。Brightness.lightBrightness.darkがあります。
primaryColor アプリの基本色になります。AppBarTabBarFloatingActionButtonなど、アプリのメインとなるWidgetの背景色がこれになります
primaryColorBrightness primaryColorにのみ適用されるbrightnessです。下のprimaryColorLightprimaryColorDarkのどちらを使うかが決まります。
primaryColorLight Brightness.lightが指定されているときの primaryColor
primaryColorDark Brightness.darkが指定されているときの primaryColor
canvasColor MaterialType(Material Designの構成要素のこと、button``card``circleなどがある)のうち Material.canvasに適用される色です。
accentColor アプリのアクセントカラーです。ScrollViewをいっぱいまでスクロールしたときにでるoverscroll edge effectなどの色になります
accentColorBrightness accentColorにのみ適用されるbrightnessです。下のprimaryColorLightprimaryColorDarkのどちらを使うかが決まります。
scaffoldBackgroundColor ScaffoldWidgetの背景色です。
bottomAppBarColor BottomAppBarWidgetの背景色です。
cardColor MaterialWidgetにtype: MaterialType.cardを指定したときやCardWidgetの背景色です。
dividerColor DividerWidgetの色です。
focusColor Widgetがフォーカスされたときの色です。TextFieldの編集中の色などになります。
hoverColor Widgetがホバーされたときの色です。
splashColor InkWellsplashの色です。inkwell
highlightColor InkWellhighlightの色です。
splashFactory InkWellsplashの効果をカスタマイズできるファクトリクラスを指定します。
selectedRowColor 選択行の背景色です。デフォルトでは特に使われていません。
unselectedWidgetColor 選択されていないWidgetの色です。CheckBox などの非選択時の色として、accentColorとの対で使われます。
disabledColor 非有効化されたWidgetの色です。押せないCheckBoxの色などに使われます。
buttonTheme RaisedButtonなどのButton系Widgetのデフォルトの設定に使われます。サイズ、色、内部のTextWidgetのスタイルなど、さまざまな値が指定できます。
toggleButtonsTheme ToggleButtons版のButtonTheme
buttonColor RaisedButtonなどのButton系Widgetの背景色です。
secondaryHeaderColor PaginatedDataTableのヘッダーの色です。
textSelectionColor TextFieldなど選択可能なTextWidgetの選択時の色です。
cursorColor TextFieldなどのカーソルの色です。
textSelectionHandleColor TextFieldなどで、文字を選択しているときのカーソルの色です。
backgroundColor 背景色のうち、primaryColorが使われない部分の色です。ProgressIndicatorの残りの部分の色などに使われます。
dialogBackgroundColor Dialogの背景色です。
indicatorTheme TabBarの選択時のインジケーターの色です。
hintColor TextFieldhintTextの色です。
errorColor エラーの色です。TextFieldのエラー文の色などに使われます。
toggleableActiveColor Switch``Radio``CheckBoxなどのトグルできるボタンの選択時の色です。
textTheme TextWidgetの基本的なスタイルです。body1``body2``title``caption``buttonなどのタイプに対するTextStyleを詰め合わせたものです。
primaryTextTheme primaryColorに対応するTextThemeです。
accentTextTheme accentColorに対応するTextThemeです。
inputDecorationTheme TextFieldなどに設定するInputDecorationThemeです。hintや枠線などを指定できます。
iconTheme IconWidgetのThemeです。サイズと色を指定できます。
primaryIconTheme primaryColorに対応するIconThemeです。
accentIconTheme accentColorにタイソウルIconThemeです。
sliderTheme SliderWidgetのThemeです。サイズや形などを指定できます。
tabBarTheme TabBarWidgetのThemeです。インジケーターのスタイルやサイズなどを指定できます。
tooltipTheme TooltipWidgetのThemeです。サイズや形などを指定できます。
cardTheme CardWidgetのThemeです。色や形を指定できます。
clipTheme ClipCircleなどのClip系WidgetのThemeです。色や形などを指定できます。
platform ThemeごとにTargetPlatformを指定するためのプロパティです。実際のTargetPlatformとは異なる場合もあります。
materialTapTargetSize Material系のWidgetのタップ領域を指定できます。paddingshrinkWrapから選べます。
applyElevationOverlayColor マテリアルデザインでelevation(浮いているような影が出る)エフェクトを表現する時に、overlayColorを利用するかどうかのフラグです。ダークテーマでは影の表現が難しいため、影の表現がオフになります。
pageTransitionsTheme 画面遷移にどのようなアニメーションを使うかというThemeです。AndroidiOSそれぞれ別に指定できます。
appBarTheme AppBarThemeです。色やタイトルのスタイルを指定できます。
bottomAppBarTheme BottomAppBarThemeです。色や形を指定できます。
colorScheme Widgetに制限されないカラーセットです。
snackBarTheme SnackBarWidgetのThemeです。色や形を指定できます。
dialogTheme DialogThemeです。色やテキストのスタイルが指定できます。
floatingActionButtonTheme FloatingActionButtonWidgetのThemeです。色や形が指定できます。
typography どのロケールで、どのフォントを使うかを指定します。
cupertinoOverrideTheme Cupertino系のWidget(iOSライクなデザインのWidget)のTheme
bottomSheetTheme BottomSheetWidgetのThemeです。形などを指定できます。
popupMenuTheme PopupMenuThemeです。色やテキストのスタイルが指定できます。
bannerTheme MaterialBannerWidgetのThemeです。
dividerTheme DividerWidgetのThemeです。色やサイズなどを指定できます。
buttonBarTheme ButtonBarWidgetのThemeです。サイズなどを指定できます。

11日目: Flutterを既存のAndroid/iOSアプリに組み込む :

https://itome.team/blog/2019/12/flutter-advent-calendar-day11

13日目: FlutterのPlatformViewを理解する :

https://itome.team/blog/2019/12/flutter-advent-calendar-day13