LoginSignup
8
3

Flutter アプリで使う TextStyle の定義と単純化

Last updated at Posted at 2022-01-05

こちらの記事で、 Material Design Color System や TextTheme に対応したバージョンを公開しました。
この記事のアプローチも有効な場合はあると思いますが、私の環境では新しい方を活用しています。

目的

  • アプリ内で使う TextStyle を一覧化
  • かつ、標準的なスタイル変更を単純に・便利に呼び出せるようにする
    • color
    • fontWeight

定義したいスタイル

  • Material Design Typography にのっとったスタイルのみをアプリ内で使用する
  • 用途ごとの定義 (title, body, label...)
  • スケールの定義 (large, medium, small)

改善前

  • 用途 x スケール で定数をふつうに定義すると・・・
    • 定数名が冗長
    • 定義が縦に長くて一覧性が微妙
    • 活用の拡張がめんどい
      • color を変えたい場合など、いちいち copyWith() で変更しないといけない

活用部分

  Text(
    "Normal Text!",
    style: MyTextStyles.bodyMedium,
  );

  // MyColors の定義は別に用意があるものとする

  Text(
    "Error!",
    style: MyTextStyles.bodyMedium.copyWith(
      color: MyColors.caution,
    ),
  );

  Text(
    "Large Bold Error!",
    style: MyTextStyles.bodyLarge.copyWith(
      color: MyColors.caution,
      fontWeight: FontWeight.bold,
    ),
  );

定義部分

class MyTextStyles {
  static const titleLarge = TextStyle(
    fontFamily: "Noto Sans",
    color: MyColors.black,
    fontSize: 57,
    height: 64 / 57,
    fontWeight: FontWeight.w400,
    letterSpacing: -0.25,
  );
  static const titleMedium = TextStyle(
    fontFamily: "Noto Sans",
    color: MyColors.black,
    fontSize: 45,
    height: 52 / 45,
    fontWeight: FontWeight.w400,
    letterSpacing: 0,
  );
  static const titleSmall = TextStyle(
    fontFamily: "Noto Sans",
    color: MyColors.black,
    fontSize: 36,
    height: 44 / 36,
    fontWeight: FontWeight.w400,
    letterSpacing: 0,
  );

  ...
}

改善後

活用部分

  Text(
    "Normal Text!",
    style: MyTextStyles.body,
  );

  Text(
    "Error!",
    style: MyTextStyles.body.caution,
  );

  Text(
    "Large Bold Error!",
    style: MyTextStyles.body.large.caution.bold,
  );

定義部分

import 'package:flutter/material.dart';

/// Use as:
/// Text("Hello!", styles: MyTextStyles.title.large.white);
class MyTextStyles {
  MyTextStyles._();

  static const fontFamily = "Hiragino Sans";

  static _toStyle(double fontSize, double height, FontWeight fontWeight,
      double letterSpacing,
      {Color color = MyColors.black}) {
    return TextStyle(
      fontFamily: MyTextStyles.fontFamily,
      color: color,
      fontSize: fontSize,
      // baseline 設定がうまくいかず height 指定すると下寄りの文字になってしまうので、適用を保留
      // height: height / fontSize,
      fontWeight: fontWeight,
      letterSpacing: letterSpacing,
    );
  }

  static final title = _MyTextStyleSet(
    large: _toStyle(22, 28, FontWeight.w400, 0),
    medium: _toStyle(16, 24, FontWeight.w500, 0.15),
    small: _toStyle(14, 20, FontWeight.w500, 0.1),
  );

  static final label = _MyTextStyleSet(
    large: _toStyle(14, 20, FontWeight.w500, 0.1),
    medium: _toStyle(12, 16, FontWeight.w500, 0.5),
    small: _toStyle(11, 16, FontWeight.w500, 0.5),
  );

  static final body = _MyTextStyleSet(
    large: _toStyle(16, 24, FontWeight.w400, 0.15),
    medium: _toStyle(14, 20, FontWeight.w400, 0.25),
    small: _toStyle(12, 16, FontWeight.w400, 0.4),
  );

  static final link = _MyTextStyleSet(
    large: _toStyle(16, 24, FontWeight.w400, 0.15, color: MyColors.textlink),
    medium: _toStyle(14, 20, FontWeight.w400, 0.25, color: MyColors.textlink),
    small: _toStyle(12, 16, FontWeight.w400, 0.4, color: MyColors.textlink),
  );
}

/// Wrapper for TextStyle
class _MyTextStyle extends TextStyle {
  _MyTextStyle(TextStyle style)
      : super(
          color: style.color,
          backgroundColor: style.backgroundColor,
          fontSize: style.fontSize,
          fontWeight: style.fontWeight,
          fontStyle: style.fontStyle,
          letterSpacing: style.letterSpacing,
          wordSpacing: style.wordSpacing,
          textBaseline: style.textBaseline,
          height: style.height,
          leadingDistribution: style.leadingDistribution,
          locale: style.locale,
          foreground: style.foreground,
          background: style.background,
          shadows: style.shadows,
          fontFeatures: style.fontFeatures,
          decoration: style.decoration,
          decorationColor: style.decorationColor,
          decorationStyle: style.decorationStyle,
          decorationThickness: style.decorationThickness,
          debugLabel: style.debugLabel,
          overflow: style.overflow,
        );

  _MyTextStyle get black => _MyTextStyle(copyWith(color: MyColors.black));
  _MyTextStyle get white => _MyTextStyle(copyWith(color: MyColors.white));
  _MyTextStyle get caution => _MyTextStyle(copyWith(color: MyColors.caution));

  _MyTextStyle get bold => _MyTextStyle(copyWith(fontWeight: FontWeight.w700));
}

class _MyTextStyleSet extends _MyTextStyle {
  final _MyTextStyle large;
  // medium is this
  final _MyTextStyle small;

  _MyTextStyleSet(
      {required TextStyle large,
      required TextStyle medium,
      required TextStyle small})
      : large = _MyTextStyle(large),
        small = _MyTextStyle(small),
        super(medium);
}
8
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3