[Flutter] Form 알아보기

디자인 감각이라고는 쥐뿔도 없지만 그래도 앱이나 웹이든 온전한 나만의 서비스를 만들고 싶었다. 그래서 앱 개발을 배우고 싶었다. 몇 년 전과는 달리 이제는 AI의 발전으로 간단한 앱 디자인 정도는 프롬프트 몇 번 적으면 될 수 있을 것 같으니 지금이 앱 개발을 배우기 딱 좋은 것 같았다. 그래서 먼저 Flutter를 통해 앱 개발에 대해 배워 보려고 한다.

아무래도 처음부터 배우기 때문에 무엇을 먼저 구현하면서 배워볼 까 하니 웹이든 앱이든 사용자가 가장 먼저 만나는 요소 중 하나인 로그인 회원 가입과 관련된 기능을 구현해 봐야겠다고 생각했다. 그래서 먼저 Form에 대해서 배워 볼까 한다.


Form

Form은 사용자 입력을 처리하기 위한 컨테이너 위젯이다. 내부에 여러개의 TextFormField 같은 위젯을 포함시켜 전체 입력값을 함께 관리하고, 유효성 검사를 할 수 있게 해 준다.

주요 기능

1. 유효성 검사 (validate)

Form에 포함된 TextFormField들은 각각 validator 함수를 가질 수 있다. FormState.validate()를 호출하면 이 함수들이 실행되어 모든 필드가 유효한지 확인한다.

2. 값 저장 (save)

FormState.save()를 호출하면 각 입력 필드의 onSaved 콜백이 호출된다. 입력값을 한 번에 저장할 수 있다.

3. 폼 상태 접근

GlobalKey<FormState>를 통해 Form의 상태를 제어할 수 있다 (예: validate, save, reset 등).

예시

더보기
import 'package:flutter/material.dart';

final _formKey = GlobalKey<FormState>();

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Study login')),
        body: Form(
          key: _formKey,
          child: Column(
            children: [
              TextFormField(
                decoration: InputDecoration(labelText: '이메일'),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return '이메일을 입력해주세요';
                  }
                  return null;
                },
              ),
              TextFormField(
                obscureText: true,
                decoration: InputDecoration(labelText: '비밀번호'),
                validator: (value) {
                  if (value == null || value.length < 6) {
                    return '6자 이상 입력해주세요';
                  }
                  return null;
                },
              ),
              ElevatedButton(
                onPressed: () {
                  if (_formKey.currentState!.validate()) {
                    print('로그인 진행');
                  }
                },
                child: Text('로그인'),
              ),
            ],
          ),
        ),
      ),
    ),
  );
}

TextFormField

TextFormField는 Flutter에서 폼 입력을 처리할 때 가장 핵심적인 위젯 중 하나다.

속성 설명
controller 입력값을 코드에서 직접 제어할 수 있도록 해주는 컨트롤러 (TextEditingController)
initialValue 초기 입력값 (단, controller가 없을 때만 사용 가능)
keyboardType 키보드 유형 지정 (이메일, 숫자, 비밀번호 등) → 예: TextInputType.emailAddress
obscureText true로 설정 시 입력값을 숨김 처리 (비밀번호 입력에 사용)
maxLength 입력 가능한 최대 글자 수
maxLines / minLines 입력 필드의 줄 수 조절 (멀티라인 입력 등)
decoration 입력 필드의 UI 요소 설정 (InputDecoration)
style 입력 텍스트의 스타일 (폰트, 색상 등)
textAlign 입력 텍스트의 정렬 방식 (예: 가운데 정렬 등)
validator Form 에서 validate() 호출 시 실행됨, 유효성 검사 로직 정의
onSaved FormState.save() 호출 시 실행, 값 저장 처리
autovalidateMode 입력 중 자동 유효성 검사 실행 모드 (onUserInteraction, always 등)
onChanged 사용자가 입력할 때마다 콜백 실행
onFieldSubmitted 사용자가 키보드의 "완료" 버튼 등을 눌렀을 때 실행
focusNode 포커스 상태를 직접 제어할 수 있는 객체
enabled 비활성화 여부 설정(false 면 입력 불가)
readOnly 읽기 전용으로 설정할 수 있음
autofocus 화면 로드시 자동 포커스 여부

 

textCapitalization 자동 대문자 설정. 예: TextCapitalization.words는 각 단어의 첫 글자를 대문자로
buildCounter maxLength가 있을 때 하단에 표시되는 글자 수 카운터 커스터마이징
inputFormatters 입력값을 필터링, 포맷팅하는 데 사용 (FilteringTextInputFormatter 등)
scrollPadding 키보드가 뜰 때 필드가 가려지지 않도록 패딩 조정
textDirection 텍스트 방향 (LTR 또는 RTL) 강제 설정
cursorColor, cursorWidth, cursorHeight 커서 색상/두께/높이 지정
enableSuggestions 키보드에서 자동완성 제안 기능 사용 여부 (기본 true)
enableInteractiveSelection 길게 눌러서 복사/붙여넣기 동작 허용 여부
mouseCursor 웹/데스크탑에서 마우스 커서 모양 지정
restorationId 상태 복원 시 사용되는 ID (State Restoration 용)
scribbleEnabled Apple Pencil Scribble 기능 사용 여부 (iPadOS)
selectionControls 커스텀 텍스트 선택 동작 컨트롤 (예: 복사, 붙여넣기 메뉴 바꾸기)

 


textInputAction

textInputAction은 사용자가 입력을 마친 후 누를 수 있는 키보드의 액션 버튼 종류를 지정한다. 이 속성을 사용하면 사용자 경험(UX)을 향상할 수 있으며, 특히 여러 입력 필드가 있을 때 포커스 이동 또는 제출 처리에 유용하다.

textInputAction 값 키보드에 표시되는 버튼
TextInputAction.next 다음 (→ 다음 필드로 이동)
TextInputAction.done 완료 (→ 입력 종료)
TextInputAction.go 이동 (→ 이동 처리)
TextInputAction.send 전송
TextInputAction.search 검색
TextInputAction.newline 줄바꿈 (멀티라인 입력 시)
    textInputAction와 함께 사용하면 좋은 속성은 다음과 같다.
  • focusNode : 현재 필드에 포커스를 제어하는 객체 
  • onFieldSubmitted : 사용자가 키보드 액션을 눌렀을 때 실행될 콜백 함수

inputFormatters

inputFormatters는 입력값에 필터링, 포맷팅, 자동 변환, 제한 등을 적용할 수 있도록 도와주는 속성이다. 리스트 형태로 여러 개의 포메터를 동시에 적용할 수 있다.

TextFormField(
  inputFormatters: [ ... ],
)
포매터 설명
FilteringTextInputFormatter.digitsOnly 숫자만 입력 허용
FilteringTextInputFormatter.allow(RegExp(...)) 특정 패턴만 허용
FilteringTextInputFormatter.deny(RegExp(...)) 특정 패턴 금지
LengthLimitingTextInputFormatter(n) 입력 길이 제한
TextInputFormatter (커스텀) 직접 입력 형식 변환 로직 구현 가능

1. 숫자만 입력 허용

TextFormField(
  inputFormatters: [
    FilteringTextInputFormatter.digitsOnly,
  ],
)

2. 최대 10자까지 입력 제한

TextFormField(
  inputFormatters: [
    LengthLimitingTextInputFormatter(10),
  ],
)

3. 영어 소문자와 숫자만 입력 허용

TextFormField(
  inputFormatters: [
    FilteringTextInputFormatter.allow(RegExp(r'[a-z0-9]')),
  ],
)

4. 특정 문자(예: 한글) 금지

TextFormField(
  inputFormatters: [
    FilteringTextInputFormatter.deny(RegExp(r'[ㄱ-ㅎㅏ-ㅣ가-힣]')),
  ],
)

커스텀 포매터 예시

만약 입력값을 자동으로 대문자로 변환하고 싶다면?

class UpperCaseTextFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue,
      TextEditingValue newValue,
  ) {
    return TextEditingValue(
      text: newValue.text.toUpperCase(),
      selection: newValue.selection,
    );
  }
}
TextFormField(
  inputFormatters: [UpperCaseTextFormatter()],
)