はじめに
入力中のテキスト内のURL部分について、入力に従って動的に色(テキストスタイル)を変える方法を紹介します。
テキスト中のURL部分の判別方法については、以下の記事を参考にしてください。
目標
入力中のテキスト内のURL部分のテキストスタイルを動的に変更する。
実装
テキストを入力するためのTextFormFieald
ウィジェットのソースコードは次のとおりです。
TextFormFieald
には TextEditingController
が設定できます。
サンプルコードは以下です。
TextEditingController
は入力テキストに対するコントローラになります。
TextFormField(
controller: _textEditingController, //TextEditingControllerのインスタンス
//その他のプロパティ
)
ここで、TextEditingController
の内部実装を確認すると次の通りです。
キーボードから入力したテキストがUI部分に反映されるのは、以下buildTextSpan
メソッドの部分です。
TextSpan buildTextSpan({required BuildContext context, TextStyle? style , required bool withComposing}) {
assert(!value.composing.isValid || !withComposing || value.isComposingRangeValid);
// If the composing range is out of range for the current text, ignore it to
// preserve the tree integrity, otherwise in release mode a RangeError will
// be thrown and this EditableText will be built with a broken subtree.
final bool composingRegionOutOfRange = !value.isComposingRangeValid || !withComposing;
if (composingRegionOutOfRange) {
return TextSpan(style: style, text: text);
}
final TextStyle composingStyle = style?.merge(const TextStyle(decoration: TextDecoration.underline))
?? const TextStyle(decoration: TextDecoration.underline);
return TextSpan(
style: style,
children: <TextSpan>[
TextSpan(text: value.composing.textBefore(value.text)),
TextSpan(
style: composingStyle,
text: value.composing.textInside(value.text),
),
TextSpan(text: value.composing.textAfter(value.text)),
],
);
}
UI部分に表示するべき入力ずみテキストをTextSpan
の形で返却していることがわかります。
したがって入力したテキストの表示に何らかの変更を加えたい場合は、TextEditingController
クラスを継承したカスタムクラスを作成し、buildTextSpan
メソッドをオーバライドすれば良いことがわかります。
ここではCustomTextEditingController
クラスを以下のように作成します。
また与えたテキストからURL部分を判別し、リンクを設定するAutoLinkText
クラスを既に別途定義ずみと仮定します(詳細は前回記事参照)。
class CustomTextEdittingController extends TextEditingController {
CustomTextEdittingController({String? text}) : super(text: text);
@override
TextSpan buildTextSpan(
{required BuildContext context,
TextStyle? style,
required bool withComposing}) {
assert(!value.composing.isValid ||
!withComposing ||
value.isComposingRangeValid);
return AutoLinkText.generate( // URL部分のみ別のスタイルを適用したTextSpanを返却するクラス
this.text, //入力したテキスト
hasLink: false, //リンク機能の有無のフラグ
).generate();
}
}
このCustomTextEdittingController
を使用して、次のようにTextFormField
を使用すると、入力中のテキストの正規表現によって判別されるURL部分のテキストスタイルを任意のもので表示することが可能です。
例えばURL部分のみ青文字で表示するといった仕様が想定されます。
ただしこのままでは、変換等が未確定の文字(buildTextSpan
中のvalue.composing.textInside
で取得できる範囲の文字列)につく下線が表示されないので、未確定文字に対して下線をつけてTextSpan
を返却するよう修正します。
未確定文字に対して下線をつけたくない場合はここまでのコーディングで問題ありません。
前述した通り、未確定文字はbuildTextSpan
中のvalue.composing.textInside
から取得することができます。
ここで改めてTextEditingController
のbuildTextSpan
のコードを参照すると、
return TextSpan(
style: style,
children: <TextSpan>[
TextSpan(text: value.composing.textBefore(value.text)),
TextSpan(
style: composingStyle,
text: value.composing.textInside(value.text),
),
TextSpan(text: value.composing.textAfter(value.text)),
],
);
このようにtextInside
で取得される入力が未確定な文字列の前後に分かれて、それらの文字列がtextBefore
およびtextAfter
として取得されて、それぞれの部分ごとにTextSpan
が生成されていることがわかります。
生成されたTextSpan
を最終的に一つのTextSpan
としてUIに表示する仕組みです。
したがって入力が未確定の文字列に対して下線をつけるためには次のようにCustomTextEdittingController
に変更を加えます。
class CustomTextEdittingController extends TextEditingController {
CustomTextEdittingController({String? text}) : super(text: text);
@override
TextSpan buildTextSpan(
{required BuildContext context,
TextStyle? style,
required bool withComposing}) {
assert(!value.composing.isValid ||
!withComposing ||
value.isComposingRangeValid);
//入力確定済みのテキストに対しての処理
if (!value.isComposingRangeValid || !withComposing) {
return AutoLinkTextSpan.generate(
this.text,
hasLink: false,
hasUnderline: false,
).generate();
}
//入力中のテキストに対する処理
return TextSpan(
children: <TextSpan>[
TextSpan(
children: [
AutoLinkTextSpan.generate(
value.composing.textBefore(value.text),
hasLink: false,
hasUnderline: false,
).generate()
],
),
TextSpan(
children: [
AutoLinkTextSpan.generate(
value.composing.textInside(value.text),
hasLink: false,
hasUnderline: true, //下線を加えるフラグ(AutoLinkTextSpan内でTextStyle変更)
).generate()
],
),
TextSpan(
children: [
AutoLinkTextSpan.generate(
value.composing.textAfter(value.text),
hasLink: false,
hasUnderline: false,
).generate()
],
),
],
);
}
}
以上で実装したCustomTextEditingController
をTextFormField
のコントローラとして指定すると、本記事の目標である「入力中のテキスト内のURL部分のテキストスタイルを動的に変更する」が達成できます。
おわりに
入力中のテキスト内のURL部分のテキストスタイルを動的に変更する方法を紹介しました。
URL部分の判別および自動でテキストスタイルや処理をセットする方法については前回記事に詳しく解説しております。
あわせてご覧ください。