プログラミング

【Flutter】 TextFieldのborderでcolorが変わらない原因

TextFieldやTextFormFieldの枠線の色を変えたいときに、安直にInputDecorationのborderに引数を渡しても変わりませんでした。

原因を調べてみるとInputDecorationのborderは使用される場合とされない場合がありましたので、備忘録として残しておきます。

環境

Flutter ... 3.0.3

Dart ... 2.17.5

使用するborderが決定されるまで

TextFieldの装飾に使用するInputDecorationには、border関連の引数が6種類あります。

  1. border
  2. disabledBorder
  3. enabledBorder
  4. errorBorder
  5. focusedBorder
  6. focusedErrorBorder

どの引数が使用されるはinput_decorator.dart内の下記コードによって決定されます。

  // input_decorator.dart buid関数内 2132行目 ~  
  final bool isError = decoration!.errorText != null;
  InputBorder? border; // これが最終的に設定されるborder
  if (!decoration!.enabled)
    border = isError ? decoration!.errorBorder : decoration!.disabledBorder;
  else if (isFocused) // isFocusedについての詳しい解説は割愛します。名前の通りフォーカスが当たっているかを表すbool型の変数です。
    border = isError ? decoration!.focusedErrorBorder : decoration!.focusedBorder;
  else
    border = isError ? decoration!.errorBorder : decoration!.enabledBorder;
  border ??= _getDefaultBorder(themeData);
// input_decorator.dart 2078行目 ~ 
InputBorder _getDefaultBorder(ThemeData themeData) {
  final InputBorder border =  MaterialStateProperty.resolveAs(decoration!.border, materialState)
    ?? const UnderlineInputBorder();
  if (decoration!.border is MaterialStateProperty<InputBorder>) {
    return border;
  }
  if (border.borderSide == BorderSide.none) {
    return border;
  }
  final Color borderColor;
  if (decoration!.enabled || isFocused) {
    borderColor = decoration!.errorText == null
      ? _getDefaultBorderColor(themeData)
      : themeData.errorColor;
  } else {
    borderColor = ((decoration!.filled ?? false) && !(decoration!.border?.isOutline ?? false))
      ? Colors.transparent
      : themeData.disabledColor;
  }
  final double borderWeight;
  if (decoration!.isCollapsed || decoration?.border == InputBorder.none || !decoration!.enabled)
    borderWeight = 0.0;
  else
    borderWeight = isFocused ? 2.0 : 1.0;
  // ここで作成されたborderは以降defaultBorderと呼びます。
  return border.copyWith(borderSide: BorderSide(color: borderColor, width: borderWeight));
}

これを元に、borderが適用されないときに考えられる原因を解説していきます。

原因

他の引数が優先されている

ソースコードを元に、TextFieldの状態と使用されるborderの関係は以下の表にまとめられます。

状態使用されるborder
enabled == false && isError == trueerrorBorder ?? _getDefaultBorder()
enabled == false && isError == falsedisabledBorder ?? _getDefaultBorder()
enabled == true && isFocused = true && isError == truefocusedErrorBorder ?? _getDefaultBorder()
enabled == true && isFocused = true && isError == falsefocusedBorder ?? _getDefaultBorder()
enabled == true && isFocused = false && isError == trueerrorBorder ?? _getDefaultBorder()
enabled == true && isFocused = false && isError == falseenabledBorder ?? _getDefaultBorder()

表から分かる通り、どの状態においてもまずはborder以外の引数が優先されるため、border以外の引数を渡しているとborderが使用されない場合があります。

borderSide != BorderSide.noneになっている

_getDefaultBorder関数内でborderを使うか判定する箇所は下記になります。

  if (decoration!.border is MaterialStateProperty<InputBorder>) {
    return border;
  }
  if (border.borderSide == BorderSide.none) {
    return border;
  }

コードからもわかる通り、borderは MaterialStateProperty<InputBorder>のインスタンス または borderSide == BorderSide.none の場合に使用されます。

そのためborderに色などの装飾を適用した場合、borderSide != BorderSide.noneになるためborderは使用されません。

色をつけたい場合は、enabledBorderなどの他の引数を使用しましょう。

解説で間違っている箇所や他に考えられる原因がありましたら、コメントを頂けると嬉しいです。

  • この記事を書いた人
  • 最新記事

おみ

プログラミング学習やキャリアのことを発信していきます。【経歴】1999年生まれ。専門学校卒業後、大手企業やベンチャー企業でSEとして勤務。現在は某メガベンチャーでFlutterエンジニアとして働いています。

-プログラミング
-,