디자인 감각이라고는 쥐뿔도 없지만 그래도 앱이나 웹이든 온전한 나만의 서비스를 만들고 싶었다. 그래서 앱 개발을 배우고 싶었다. 몇 년 전과는 달리 이제는 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()],
)
'앱 개발 > Flutter' 카테고리의 다른 글
[Flutter] 입문 - 시작과 기초 개념 잡기 (1) | 2025.07.25 |
---|---|
[Flutter] 입문 - 화면 전환(Navigation) (0) | 2025.07.25 |
[Flutter] 입문 - 기본 위젯 & Stateful vs Stateless 이해 (0) | 2025.07.25 |