【Flutter解体新書 vol.3】ThemeData編 (頑張った…)

Dart

概要

どうも、@daiki1003です!

みなさまお久しぶりです!

解体新書vol.3を久しぶりに公開したいと思います!
vol.1, 2はこちら。

【Flutter解体新書 vol. 1】TextField.decoration篇
さて、皆さんに一つ質問です。 FlutterのWidgetって、パラメタ多すぎじゃありません?笑 そんな、あなたに朗報です。 このブログを始めとする解体新書シリーズを読めば 何を指定したら何が変わるのか、理解出来る様...
【Flutter解体新書 vol. 2】SelectableText篇
約1年前に、TextField.decorationの解体新書という記事をリリースしました。 割と好評をいただけているようなので、今回はSelectableTextについて解説したいと思います。 このブログを始め...

なお、この記事はFlutter Advent Calendar 2022、3日目の記事となります。

すごく長いので、辞書的な感じで使っていただけると幸いです!
また、各種サンプルはどこが指定されているか分かりやすくするために指定しており
デザイン的観点は全くないのでその点はご承知おきくださいませ笑
最後に、ThemeData内のコメントにも書いているように、Deprecatedなプロパティを除いてアルファベット順で表記しています。

今回のサンプルプロジェクトは下記にあるので、手元でコードをコピペしたりして遊んでみてくださいね!

GitHub - daiki1003/dismantle_flutter_widgets: Repository for flutter widgets
Repository for flutter widgets. Contribute to daiki1003/dismantle_flutter_widgets development by creating an account on GitHub.

では行ってみましょー!

執筆時環境

Flutter 3.3.8 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 52b3dc25f6 (3 weeks ago) • 2022-11-09 12:09:26 +0800
Engine • revision 857bd6b74c
Tools • Dart 2.18.4 • DevTools 2.15.0

bool? applyElevationOverlayColor

ダークテーマの際にtrueになっており、elevationの代わりにカードの色などを調節してくれるようになるフラグです。

https://github.com/flutter/flutter/blob/5005824763e1e581f3afede54bb9c85a9c42f8c5/packages/flutter/lib/src/material/elevation_overlay.dart#L40-L42

NoDefaultCupertinoThemeData? cupertinoOverrideTheme

MaterialAppでは、themeにはThemeDataしか指定できません。
しかし、iOSのUIであるCupertino系ウィジェットはThemeDataではなくCupertinoThemeDataで指定する必要があります。

その際に、こちらのプロパティを使って指定します。

Iterable? extensions

Flutter 3から使えるようになったThemeExtensionを扱うためのプロパティです。
詳しい説明はThemeExtensionの説明ブログに譲ります。

InputDecorationTheme? inputDecorationTheme

InputDecorationTheme(
  filled: true,
  fillColor: Colors.red[100],
  isDense: true,
  contentPadding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
  hintStyle: TextStyle(color: Colors.red),
),
デフォルトテーマ変更後
>

TextFieldなど入力系のウィジェットのテーマを指定できます。

MaterialTapTargetSize? materialTapTargetSize

  materialTapTargetSize: materialTapTargetSize.shrinkWrap,
デフォルトテーマ変更後

全体的に描画範囲が縮まっていることがわかりますね。

PageTransitionsTheme? pageTransitionsTheme

{ TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(), }, ),

ページ遷移のアニメーションを変更します。

FadeUpwardsPageTransitionsBuilder class - material library - Dart API
API docs for the FadeUpwardsPageTransitionsBuilder class from the material library, for the Dart programming language.
OpenUpwardsPageTransitionsBuilder class - material library - Dart API
API docs for the OpenUpwardsPageTransitionsBuilder class from the material library, for the Dart programming language.
CupertinoPageTransitionsBuilder class - material library - Dart API
API docs for the CupertinoPageTransitionsBuilder class from the material library, for the Dart programming language.
ZoomPageTransitionsBuilder class - material library - Dart API
API docs for the ZoomPageTransitionsBuilder class from the material library, for the Dart programming language.

などが指定できます。

TargetPlatform? platform

iPhone SimulatorなどでAndroidのテーマ確認をする際に、

platform: TargetPlatform.android,

とすることで、確認すると言ったことが出来ます。

Flutter の Platform 判定を正しく理解する
Flutterは、Android・iOS・Web・Windows・macOS・Linux・Fuchsia…

device_previewパッケージなんかもすごく便利ですが、サクッと確認する場合には圧倒的にこちらが楽ですね。

ScrollbarThemeData? scrollbarTheme

const ScrollbarThemeData(
  thumbColor: MaterialStatePropertyAll(Colors.yellow),
  trackColor: MaterialStatePropertyAll(Colors.black),
  trackBorderColor: MaterialStatePropertyAll(Colors.red),
  thumbVisibility: MaterialStatePropertyAll(true),
  trackVisibility: MaterialStatePropertyAll(true),
),
デフォルトテーマ変更後

InteractiveInkFeatureFactory? splashFactory

ボタンなどを押した際に、リップルエフェクトが発生しますがこれに関する設定を一括で行えます。
NoSplash.splashFactoryで抑制したり、InkSparkle.splashFactoryなどで少し速いリップルエフェクトなどを指定できます。

bool? useMaterial3

  useMaterial3: true,
デフォルトテーマ変更後

その名の通り、 Material 3を適用するかどうかのフラグとなります。
相当見た目変わりますね。

VisualDensity? visualDensity

VisualDensity.compact,
デフォルトテーマ変更後

styleプロパティなどで、visualDensityを指定出来るウィジェットのpaddingを微調整出来ます。

Color? backgroundColor

ColorSchemeによる指定が推奨されています。
後にColorによる指定やprimarySwatchなどは消すそうです。

Color? bottomAppBarColor

ColorSchemeによる指定が推奨されています。

Brightness? brightness

ColorSchemeによる指定が推奨されています。

Color? canvasColor

ColorSchemeによる指定が推奨されています。

Color? cardColor

ColorSchemeによる指定が推奨されています。

ColorScheme? colorScheme

ColorSchemeによる指定が推奨されています。

Color? colorSchemeSeed

ColorSchemeによる指定が推奨されています。

Color? dialogBackgroundColor

ColorSchemeによる指定が推奨されています。

Color? disabledColor

ColorSchemeによる指定が推奨されています。

Color? dividerColor

ColorSchemeによる指定が推奨されています。

Color? errorColor

ColorSchemeによる指定が推奨されています。

Color? focusColor

ColorSchemeによる指定が推奨されています。

Color? highlightColor

ColorSchemeによる指定が推奨されています。

Color? hintColor

ColorSchemeによる指定が推奨されています。

Color? hoverColor

ColorSchemeによる指定が推奨されています。

Color? indicatorColor

ColorSchemeによる指定が推奨されています。

Color? primaryColor

ColorSchemeによる指定が推奨されています。

Color? primaryColorDark

ColorSchemeによる指定が推奨されています。

Color? primaryColorLight

ColorSchemeによる指定が推奨されています。

MaterialColor? primarySwatch

ColorSchemeによる指定が推奨されています。

Color? scaffoldBackgroundColor

ColorSchemeによる指定が推奨されています。

Color? secondaryHeaderColor

ColorSchemeによる指定が推奨されています。

Color? selectedRowColor

ColorSchemeによる指定が推奨されています。

Color? shadowColor

ColorSchemeによる指定が推奨されています。

Color? splashColor

ColorSchemeによる指定が推奨されています。

Color? toggleableActiveColor

ColorSchemeによる指定が推奨されています。

Color? unselectedWidgetColor

ColorSchemeによる指定が推奨されています。

String? fontFamily

textThemeprimaryTextThemeの設定に用いられています。

IconThemeData? iconTheme

const IconThemeData(
  color: Colors.red,
  opacity: 0.3,
),
デフォルトテーマ変更後

IconIconButtonはもちろんのこと、PopupMenuButtonchild未指定時の
三点リーダにも適用されているようです。

IconThemeData? primaryIconTheme

primaryColorの上に表示するアイコン用のテーマです。
leadingactionsの表示の際に、サイズが参照されていたりもします。

TextTheme? primaryTextTheme

TextTheme(
  subtitle1: TextStyle(
    fontSize: 10,
    color: Colors.red,
  ),
)

primaryColorの上に表示するテキスト用のテーマです。
CircleAvatarchildTextを指定した際などに使われたりしていますね。

TextTheme? textTheme

その名の通り、Textのテーマです。

Typography? typography

内部的に、上記 textThemeを生成するために使用されています。
Typographyクラスには、Material 3に対応したTypography.material2021
それ以前であるTypography.material2014などのコンストラクタを持っています。

AppBarTheme? appBarTheme

const AppBarTheme(
  backgroundColor: Colors.blueGrey,
  elevation: 0,
),
デフォルトテーマ変更後

MaterialBannerThemeData? bannerTheme

MaterialBannerThemeData(
  padding: EdgeInsets.all(20),
  backgroundColor: Colors.grey[200],
),
デフォルトテーマ変更後

BottomAppBarTheme? bottomAppBarTheme

BottomAppBarTheme(
  color: Colors.red,
)
デフォルトテーマ変更後

FABと相性の良いBottomAppBarのためのテーマです。

BottomNavigationBarThemeData? bottomNavigationBarTheme

BottomNavigationBarThemeData(
  backgroundColor: Colors.black12,
  elevation: 0,
  unselectedIconTheme: IconThemeData(
    size: 16,
  ),
  unselectedLabelStyle: TextStyle(
    fontSize: 10,
  ),
  selectedIconTheme: IconThemeData(
    size: 24,
    color: Colors.red,
  ),
  selectedLabelStyle: TextStyle(
    fontSize: 16,
  ),
  selectedItemColor: Colors.red,
),
デフォルトテーマ変更後

画面下部のBottomNavigationBarのためのテーマです。

BottomSheetThemeData? bottomSheetTheme

const BottomSheetThemeData(
 backgroundColor: Colors.red,
),
デフォルトテーマ変更後

BottomSheetのテーマです。
showModalBottomSheetを用いて表示した際は、modalBackgroundColormodalElevationが使用されます。

ButtonBarThemeData? buttonBarTheme

const ButtonBarThemeData(
  mainAxisSize: MainAxisSize.min,
  buttonTextTheme: ButtonTextTheme.primary,
  overflowDirection: VerticalDirection.up,
),
デフォルトテーマ変更後

ButtonBarのテーマを指定できます。

ButtonThemeData? buttonTheme

各種ボタンの色などのテーマを指定するものですが、廃止予定です。
後述する、elevatedButtonThemeなど個別で指定しましょう。

CardTheme? cardTheme

CardTheme(
  color: Colors.red,
  elevation: 12,
),
デフォルトテーマ変更後

Cardのテーマを指定します。
カード自体の色や影の色やサイズを指定することができます。

CheckboxThemeData? checkboxTheme

CheckboxThemeData(
  fillColor: MaterialStatePropertyAll(Colors.red[100]),
  checkColor: MaterialStatePropertyAll(Colors.red)
),
デフォルトテーマ変更後

Checkboxのテーマを指定します。

ChipThemeData? chipTheme

ChipThemeData(
  backgroundColor: Colors.red[100],
  disabledColor: Colors.green,
  selectedColor: Colors.blue,
  showCheckmark: true,
  checkmarkColor: Colors.amber,
),
デフォルトテーマ変更後

各種Chipと名のつくクラスのテーマを指定することができます。
一部のChipにしか対応していないプロパティなどもあるので注意が必要です。

DataTableThemeData? dataTableTheme

DataTableThemeData(
  columnSpacing: 120,
  headingRowColor: MaterialStatePropertyAll(Colors.red),
  headingRowHeight: 32,
  dataRowColor: MaterialStatePropertyAll(Colors.red),
),
デフォルトテーマ変更後

DatTableのテーマを指定することができます。
DataTableeを生成する際には、columnsrowsなのに、テーマは
headerRowdataRowなのが少し気になりますね笑

DialogTheme? dialogTheme

DialogTheme(
  backgroundColor: Colors.red[100],
  elevation: 0,
  titleTextStyle: TextStyle(color: Colors.blue),
  contentTextStyle: TextStyle(color: Colors.green),
),
デフォルトテーマ変更後

SimpleDialogAlertDialogのテーマを指定することができます。

DividerThemeData? dividerTheme

DividerThemeData(
  color: Colors.red[300],
  thickness: 4,
  indent: 16,
  endIndent: 16,
),
デフォルトテーマ変更後

Dividerのテーマを指定することができます。

DrawerThemeData? drawerTheme

DrawerThemeData(
  backgroundColor: Colors.red[100],
  scrimColor: Colors.blue[300],
  elevation: 0,
),
デフォルトテーマ変更後

Drawerを開いた際のテーマを指定することができます。

ElevatedButtonThemeData? elevatedButtonTheme

ElevatedButtonThemeData(
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.red[100],
    foregroundColor: Colors.red,
    disabledBackgroundColor: Colors.grey[100],
    disabledForegroundColor: Colors.grey,
    textStyle: const TextStyle(fontSize: 24),
    elevation: 1,
  ),
),
デフォルトテーマ変更後

ElevatedButtonのテーマを指定することができます。

ExpansionTileThemeData? expansionTileTheme

ExpansionTileThemeData(
  backgroundColor: Colors.red[100],
  collapsedBackgroundColor: Colors.red,
  iconColor: Colors.black,
  collapsedIconColor: Colors.white,
  textColor: Colors.black,
  collapsedTextColor: Colors.white,
),
デフォルトテーマ変更後

ExpantionTileのテーマを指定することができます。

FloatingActionButtonThemeData? floatingActionButtonTheme

FloatingActionButtonThemeData(
  backgroundColor: Colors.red[100],
  foregroundColor: Colors.red,
  elevation: 1,
  iconSize: 16,
),
デフォルトテーマ変更後

FloatingActionButtonのテーマを指定することができます。

ListTileThemeData? listTileTheme

ListTileThemeData(
  iconColor: Colors.red,
  horizontalTitleGap: 50,
  contentPadding: EdgeInsets.all(10),
  tileColor: Colors.red[100],
  textColor: Colors.red,
),
デフォルトテーマ変更後

ListTileのテーマを指定することができます。

NavigationBarThemeData? navigationBarTheme

NavigationBarThemeData(
  height: 80,
  backgroundColor: Colors.red[100],
  indicatorColor: Colors.red,
  indicatorShape: const StadiumBorder(),
  labelTextStyle: const MaterialStatePropertyAll(TextStyle(
    fontSize: 12,
    color: Colors.red,
  )),
  iconTheme: MaterialStateProperty.resolveWith((states) {
    if (states.contains(MaterialState.selected)) {
      return const IconThemeData(
        color: Colors.white,
      );
    }
    return const IconThemeData(
      color: Colors.red,
    );
  }),
),
デフォルトテーマ変更後

NavigationBarのテーマを指定することができます。

NavigationRailThemeData? navigationRailTheme

NavigationRailThemeData(
  backgroundColor: Colors.red[100],
  elevation: 10,
  unselectedLabelTextStyle: const TextStyle(color: Colors.red),
  unselectedIconTheme: const IconThemeData(color: Colors.red),
  selectedLabelTextStyle: const TextStyle(
    fontSize: 24,
    color: Colors.white,
  ),
  selectedIconTheme: const IconThemeData(
    color: Colors.white,
  ),
  useIndicator: true,
  indicatorColor: Colors.amber,
  labelType: NavigationRailLabelType.all,
  minWidth: 100,
),
デフォルトテーマ変更後

OutlinedButtonThemeData? outlinedButtonTheme

OutlinedButtonThemeData(
  style: OutlinedButton.styleFrom(
    backgroundColor: Colors.red[100],
    foregroundColor: Colors.red,
    disabledBackgroundColor: Colors.grey[100],
    disabledForegroundColor: Colors.grey,
    textStyle: const TextStyle(fontSize: 24),
    elevation: 1,
  ),
),
デフォルトテーマ変更後

OutlinedButtonのテーマを指定できます。

PopupMenuThemeData? popupMenuTheme

PopupMenuThemeData(
  color: Colors.red[100],
  textStyle: const TextStyle(
    fontSize: 24,
    color: Colors.red,
  ),
),
デフォルトテーマ変更後

PopupMenuButtonPopupMenuItemのテーマを指定できます。

ProgressIndicatorThemeData? progressIndicatorTheme

ProgressIndicatorThemeData(
  color: Colors.red,
  linearTrackColor: Colors.green,
  linearMinHeight: 8,
  circularTrackColor: Colors.amber,
  refreshBackgroundColor: Colors.blue,
),
デフォルトテーマ変更後

CircularProgressIndicatorLinearProgressIndicatorのテーマを指定できます。
ただし、ThemeDataMaterial UIが対象なので、iOS端末においてCircularProgressIndicator.adaptiveなどで
表示した場合は適用されません。

RadioThemeData? radioTheme

RadioThemeData(
  fillColor: MaterialStatePropertyAll(Colors.red),
)
デフォルトテーマ変更後

RadioRadioListTileなどのテーマを指定できます。

SliderThemeData? sliderTheme

SliderThemeData(
  trackHeight: 8,
  activeTrackColor: Colors.blue[100],
  inactiveTrackColor:Colors.red[100], 
  thumbColor: Colors.red,
),
デフォルトテーマ変更後

Sliderのテーマを指定できます。

SnackBarThemeData? snackBarTheme

SnackBarThemeData(
  backgroundColor: Colors.red[100],
  contentTextStyle: TextStyle(color: Colors.red),
  actionTextColor: Colors.black,
),
デフォルトテーマ変更後

Snackbarのテーマを指定できます。

SwitchThemeData? switchTheme

SwitchThemeData(
  thumbColor: MaterialStatePropertyAll(Colors.red),
  trackColor: MaterialStatePropertyAll(Colors.red[100]),
),
デフォルトテーマ変更後

Switchのテーマを指定できます。
ただし、ThemeDataMaterial UIが対象なので、iOS端末においてSwitch.adaptiveなどで
表示した場合は適用されません。

TabBarTheme? tabBarTheme

TabBarTheme(
  labelColor: Colors.red,
  unselectedLabelColor: Colors.green,
  indicator: BoxDecoration(
    color: Colors.red[100],
    borderRadius: BorderRadius.circular(16),
  ),
  labelPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
  indicatorSize: TabBarIndicatorSize.tab,
),
デフォルトテーマ変更後

TabBarのテーマを指定できます。

TextButtonThemeData? textButtonTheme

TextButtonThemeData(
  style: TextButton.styleFrom(
    backgroundColor: Colors.red[100],
    foregroundColor: Colors.red,
    disabledForegroundColor: Colors.blue,
    disabledBackgroundColor: Colors.blue[100],
    textStyle: const TextStyle(fontSize: 24),
    padding: const EdgeInsets.all(20),
  ),
),
デフォルトテーマ変更後

TextSelectionThemeData? textSelectionTheme

TextSelectionThemeData(
  selectionColor: Colors.red[100],
  selectionHandleColor:  Colors.green,
),
デフォルトテーマ変更後

SelectableTextなどで、テキストを範囲選択した際のセレクタのテーマを指定できます。

TimePickerThemeData? timePickerTheme

TimePickerThemeData(
  backgroundColor: Colors.red[100],
  hourMinuteTextColor: Colors.red,
  hourMinuteColor: Colors.blue[100],
  dayPeriodColor: Colors.green[100],
  dayPeriodTextColor: Colors.green,
  dialBackgroundColor: Colors.blue[100],
  dialHandColor: Colors.blue,
  dialTextColor: Colors.blue,
  entryModeIconColor: Colors.yellow,
  hourMinuteShape: const StadiumBorder(),
  hourMinuteTextStyle: const TextStyle(fontSize: 24),
  dayPeriodTextStyle: const TextStyle(fontSize: 20),
  helpTextStyle: const TextStyle(fontSize: 20),
),
デフォルトテーマ変更後

showTimePickerで出るピッカーのテーマを指定できます。
かなり色々自由に指定できそうですね。

ToggleButtonsThemeData? toggleButtonsTheme

ToggleButtonsThemeData(
  color: Colors.blue,
  fillColor: Colors.red[100],
  borderColor: Colors.red[100],
  selectedBorderColor: Colors.red,
  borderRadius: BorderRadius.circular(16),
  selectedColor: Colors.red,
  disabledColor: Colors.black,
  disabledBorderColor: Colors.black,
  borderWidth: 8,
),
デフォルトテーマ変更後

TooltipThemeData? tooltipTheme

TooltipThemeData(
  height: 64,
  padding: const EdgeInsets.all(10),
  verticalOffset: 40,
  decoration: BoxDecoration(
    color: Colors.red[100],
  ),
  textStyle: const TextStyle(
    fontWeight: FontWeight.bold,
    color: Colors.red,
  ),
),
デフォルトテーマ変更後

各種ウィジェットのTooltipのテーマを指定できます。

ここから下はDeprecatedとなっています。

Color? accentColor

その名の通り、アクセント色を指定することが出来ました。
ColorScheme.secondaryを代わりに使ってください。

Brightness? accentColorBrightness

現在使われていません。

TextTheme? accentTextTheme

現在使われていません。

IconThemeData? accentIconTheme

現在使われていません。

Color? buttonColor

現在使われていません。

bool? fixTextFieldOutlineLabel

指定せずともデフォルトで有効です。

Brightness? primaryColorBrightness

現在使われていません。

AndroidOverscrollIndicator? androidOverscrollIndicator

useMaterial3を使うか、ScrollBehavior.buildOverscrollIndicatorを使ってください。

終わりに

いかがでしたでしょうか?

Themeは開発途中から入れるには影響範囲が大きすぎて入れづらいですよね。
どこが変化するのか正しく把握して最初から設計しておきたいですね!
僕も頑張ります笑

もし、間違いがあったらTwitterまで指摘などをお願いします!

頑張ったねって少しでも思っていただけたら↓からコーヒーを少し奢っていただけると嬉しいです!
もちろん、強制ではありません笑

誰かのお役に立てば。

Twitterフォローお願いします

「次回以降も記事を読んでみたい!」
「この辺分からなかったから質問したい!」

そんな時は、是非Twitter (@daiki1003)Instagram (@ashdik_flutter)のフォローお願いします♪

Twitterコミュニティ参加お願いします

Twitterコミュニティ「Flutter lovers」を開設しました!
参加お待ちしております😁

☕️ Buy me a coffee

また、記事がとても役に立ったと思う人は
コーヒーを奢っていただけると非常に嬉しいです!
@daiki1003

コメント

タイトルとURLをコピーしました