이번 글에서는 TextField를 사용할 때에 입력된 텍스트의 스타일을 각각 다르게 해주는 기능에 대해서 살펴보려고 한다.
일반적인 텍스트 입력창은 TextFormField의 style 파라미터를 지정해 텍스트의 스타일을 사용하고 있다. SNS의 사용자 태그 기능이나 하이퍼 텍스트 기능 등을 사용하려고 하면 입력된 텍스트와 태그된 텍스트의 스타일이 다른 것을 확인할 수 있다.
이런 기능은 어떻게 만들어야 할까 ? 최근에 해당 기능이 필요해서 이것저것 알아보는데, 생각보다 정리된 글들이 많이 없어서 글을 작성하게 되었다.
Flutter에서 텍스트 입력창을 하나 만들어 보자.
입력창을 생성하는데 주로 TextFormField를 사용하게 되고, 아래 코드와 같이 style에 TextStyle을 지정해서 입력된 텍스트 스타일을 지정해주게 된다.
하지만 해당 방식으로 사용하면 텍스트 스타일을 각각 다르게 지정할 수가 없다.
텍스트 입력창이 아니더라도 일반적인 Text 객체로는 스타일을 다르게 지정할 수 없고 TextSpan을 사용해야 한다는 것을 알고 있을 것이다.
final TextEditingController controller = TextEditingController();
TextFormField(
controller: controller,
style: const TextStyle(
color: Colors.green,
fontSize: 14,
fontWeight: FontWeight.bold,
),
decoration: const InputDecoration(
contentPadding: EdgeInsets.only(left: 8, right: 8),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
errorBorder: InputBorder.none,
),
),
텍스트 입력창의 텍스트를 TextSpan으로 사용하면 될 것 같다.
TextEditingController를 살펴보면 buildTextSpan이라는 기능이 있어서 TextFormField도 TextSpan으로 사용할 수 있을 것이라 생각이 들었다.
controller.buildTextSpan(context: context, withComposing: withComposing)
TextEditingController를 상속받아 커스텀을 해주도록 하자.
class CustomTagController extends TextEditingController {}
위에서 살펴본 buildTextSpan을 우리가 원하는 스타일에 맞게 재정의 해주면 될 것 같다.
buildTextSpan(
{required BuildContext context,
TextStyle? style,
required bool withComposing}) {
return super.buildTextSpan(context, style, withComposing);
}
TextSpan
TextEditingController를 상속 받았기 때문에, text에 접근할 수 있게 된다. 정상적으로 작동하는지 테스트 해보자.
class CustomTagController extends TextEditingController {
TextSpan buildTextSpan({
required BuildContext context,
TextStyle? style,
required bool withComposing,
}) {
print(text);
return const TextSpan();
}
}
controller를 새롭게 만든 객체로 변경해주고 TextFormField에 선언해보자.
텍스트를 입력해보면 정상적으로 출력되는 것을 확인할 수 있다.
위에서 style 파라미터의 텍스트 스타일을 지정 하였는데, CustomTagController를 사용하니깐 디폴트 스타일로 변경된 것도 확인할 수 있다.
final CustomTagController controller = CustomTagController();
텍스트 입력차에 텍스트도 쓰여지지 않았을 것이다. TextSpan에 text, style을 지정하지 않았기 때문이다.
이제 정상적으로 변경된 스타일로 노출이 되고있다.
return TextSpan(
text: text,
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.red));
이제 입력된 텍스트에 따라 스타일을 각각 다르게 주도록 해보자.
먼저 스타일을 다르게 주기 위해 입력 받아오는 텍스트를 각각 나눠서 TextSpan을 사용해 스타일을 넣어주어야 한다.
공백을 기준으로 텍스트를 나누어 주었다.
class CustomTagController extends TextEditingController {
...
List<String> words = text.split(" ");
...
TextSpan을 배열에 담아야 하기에 배열을 먼저 선언해주자.
List<TextSpan> children = [];
공백을 기준으로 나눈 words를 반복문을 사용해 입력하는 키워드와 일치하는 키워드에만 TextSpan을 각각 넣어주면 된다.
반복문이 반복될 때마다 마지막에 항상 공백을 다시 추가해 주어야 한다. 공백을 기준으로 나눴기 때문에 words 배열안에 값들의 공백은 없어졌기 때문이다.
for (final String word in words) {
TextSpan span;
switch (word) {
case "red":
span =
TextSpan(text: word, style: const TextStyle(color: Colors.red));
break;
case "orange":
span = TextSpan(
text: word, style: const TextStyle(color: Colors.orange));
break;
case "amber":
span =
TextSpan(text: word, style: const TextStyle(color: Colors.amber));
break;
case "green":
span =
TextSpan(text: word, style: const TextStyle(color: Colors.green));
break;
case "purple":
span = TextSpan(
text: word, style: const TextStyle(color: Colors.purple));
break;
case "pink":
span =
TextSpan(text: word, style: const TextStyle(color: Colors.pink));
break;
default:
span =
TextSpan(text: word, style: const TextStyle(color: Colors.white));
break;
}
children.add(span);
children.add(const TextSpan(text: " "));
}
이제 TextSpan의 children에 넣어서 리턴해주면 된다.
return TextSpan(children: children);
색상뿐만 아니라 스타일에서 지정가능한 모든 것을 변경할 수 있다.
텍스트 입력창에서 텍스트 스타일을 다르게 주는 방법을 다들 이해했을 것이다.
이제 SNS에 사용자를 태그하는 텍스트 입력창을 만들 수 있다.
https://github.com/boglbbogl/flutter_velog_sample/blob/main/lib/ui/sns_tag/sns_tag_screen.dart
텍스트 입력창에서 TextSpan을 사용하는 방법에 대해서 간단하게 사용해 봤다.
SNS Tag와 같은 기능은 Git 저장소에서 코드 확인할 수 있습니다.
감사합니다!!!!!!!!!