Flutter의 TextField위젯에서 입력을 받다보면, 정규식을 이용해야 할 때가 온다.

TextField(
  inputFormatters: [
    FilteringTextInputFormatter.deny(RegExp(r'[/\\]')),
  ],
)

검색을 하다보면, 늘 그렇듯이 내가 원하는 입맛에 딱 맞는 코드는 안나오는게 국룰.
이 글을 보는 독자들도 딱 입맛에 맞는 것은 아니겠지만, 최대한 큰 틀에서 설명 해보고자 한다.

우선 TextField 위젯 안에는 inputFormatters라는 파라미터가 있다.

final List<TextInputFormatter>? inputFormatters;

TextInputFormatter 는 abstract 클래스로 구성되어있다.

abstract class TextInputFormatter {
  /// Called when text is being typed or cut/copy/pasted in the [EditableText].
  ///
  /// You can override the resulting text based on the previous text value and
  /// the incoming new text value.
  ///
  /// When formatters are chained, `oldValue` reflects the initial value of
  /// [TextEditingValue] at the beginning of the chain.
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  );

그래서 ㅇㅉㄹㄱ,,,
그러니까, TextInputFormatter를 참조하는 FilteringTextInputFormatter 클래스가 있다.

FilteringTextInputFormatter(
    this.filterPattern, {
    required this.allow,
    this.replacementString = '',
  }) : assert(filterPattern != null),
       assert(allow != null),
       assert(replacementString != null);

따라서, FilteringTextInputFormatter를 사용하면 된다.

✏️ Ex. 숫자만 입력가능하게

  • FilteringTextInputFormatter.digitsOnly
  • FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))

Full Code

TextFormField(
          keyboardType: TextInputType.number,
          inputFormatters: [
            FilteringTextInputFormatter.digitsOnly
          ],
        ),
        
또는
TextFormField(
          keyboardType: TextInputType.number,
          inputFormatters: [
            FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))
          ],
        ),

이런식으로 사용할 수 있다.

내가 적용하고자 했던것.

✏️ 1. 4자리의 숫자(1000단위까지만)

final inputFormatter = FilteringTextInputFormatter.allow(RegExp(r'^[1-9]{1}.{0,5}'));

✏️ 2. 1000단위 부터는 ,(separator) 붙이기.

class UnitInputFormatter extends TextInputFormatter {
  UnitInputFormatter(this.unit);
  final Unit unit;
  static const separator = ',';
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    String oldValueText = oldValue.text.replaceAll(separator, '');
    String newValueText = newValue.text.replaceAll(separator, '');

    if (newValue.selection.baseOffset == 0) {
      return newValue;
    }
    if (oldValue.text.endsWith(separator) &&
        oldValue.text.length == newValue.text.length + 1) {
      newValueText = newValueText.substring(0, newValueText.length - 1);
    }

    // Only process if the old value and new value are different
    if (oldValueText != newValueText) {
      int selectionIndex =
          newValue.text.length - newValue.selection.extentOffset;
      final chars = newValueText.split('');

      String newString = '';
      for (int i = chars.length - 1; i >= 0; i--) {
        if ((chars.length - 1 - i) % 3 == 0 && i != chars.length - 1)
          newString = separator + newString;
        newString = chars[i] + newString;
      }

      return TextEditingValue(
        text: newString.toString() + unit.enumToString(),
        selection: TextSelection.collapsed(
          offset: newString.length - selectionIndex,
        ),
      );
    }

1번 변수를 만들고, 2번 클래스를 만든 뒤,inputFormattes에 추가해줌.

TextField(
	inputFormatters: [
                  calorieInputFormatter,
                  CalorieUnitInputFormatter(Unit.kcal),
                 ]
              ),
profile
Hello Universe!

0개의 댓글