달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
반응형

최근 Flutter TextField에서 숫자 입력 시 천 단위 마다 콤마를 표시되도록 해야하는 일이 생겼는데

이게 생각보다 간단하지 않았다. 

일단 숫자 입력만 되도록 제한하고 천 단위 마다 콤마 표시하는 것 자체는 크게 어렵지 않았는데,

콤마를 표시하면 그것도 자리 차지를 하게 되어 중간에서 입력/삭제 후 자연스러운 커서 위치를 잡기가 어려웠지만

규칙을 찾아 수식을 작성해서 해결했다.

 

완성된 코드는 다음과 같다.

import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

class ThousandCommaTextField extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color(0xffffffff),
      body: SafeArea(
        child: Container(
          padding: EdgeInsets.all(10),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              TextField(
                keyboardType: TextInputType.number,
                textAlign: TextAlign.right,
                inputFormatters: <TextInputFormatter>[
                  FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
                  FilteringTextInputFormatter.digitsOnly,
                  ThousandCommaInputFormatter()
                ],
              )
            ],
          )
        )
      ),
    );
  }
}

String thousandComma(dynamic val, {String defaultVal = ""}) {
  NumberFormat numberFormat = NumberFormat('#,###', "ko_KR");
  if (val != null && val != "") {
    if (val is int || val is double) {
      return numberFormat.format(val);
    } else if (double.tryParse(val) != null) {
      return numberFormat.format(double.parse(val));
    } else if (int.tryParse(val) != null) {
      return numberFormat.format(int.parse(val));
    }
  }

  return defaultVal;
}

class ThousandCommaInputFormatter extends TextInputFormatter {
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    String oldNum = oldValue.text.replaceAll(",", "");
    String newNum = newValue.text.replaceAll(",", "");

    String newText = thousandComma(newValue.text, defaultVal: "0");

    // 다음 커서 위치 잡기
    int selectionIndex = ((newValue.text.length -1) / 3).floor() // 전체 ,(comma)의 수
                        - (((newValue.text.length - newValue.selection.end)-1) / 3).floor() //현재 커서 위치를 기준으로 오른쪽에 있는 ,(comma)의 수
                        + newValue.selection.end;

    if (selectionIndex > newText.length) {
      selectionIndex = newText.length;
    }

    if (oldNum == newNum) {//,(comma) 뒤에 커서놓고 삭제 시
      //1,234,567에서 4,뒤(커서 위치 6)에서 삭제하면 123,567이 되므로 1뒤의 ,와 4가 같이 없어져서 커서 위치가 2만큼 왼쪽으로 이동해야 한다. (최종 커서 위치 4가 되야함)
      //98,765에서 8,뒤(커서 위치 3)에서 삭제하면 9,765가 되므로 8만 없어져서 커서 위치가 1만큼 왼쪽으로 이동해야 한다. (최종 커서 위치 2가 되야함)
      selectionIndex = selectionIndex - (newText.replaceAll(",", "").length % 3 == 1 ? 2 : 1);
      newText = newValue.text.substring(0, newValue.selection.end - 1) + newValue.text.substring(newValue.selection.end);
      newText = thousandComma(newText, defaultVal: "0");
    }

    return newValue.copyWith(
        text: newText,
        selection: TextSelection.collapsed(
            offset: selectionIndex));
  }
}

 

 

참고 출처:

https://stackoverflow.com/questions/49577781/how-to-create-number-input-field-in-flutter

https://stackoverflow.com/questions/61866207/thousand-separator-without-decimal-separator-on-textformfield-flutter

반응형
:
Posted by 리샤씨