본문 바로가기
앱개발/flutter

[Flutter] TextField, TextFormField, TextEditingController

by 씐 2025. 3. 20.
728x90

TextField

특징

  • 사용자 입력을 받을 때 사용되는 가장 기본적인 위젯
  • 주로 단순한 텍스트 입력, 실시간 데이터 처리에 사용됨.

 

예시코드

import 'package:flutter/material.dart';

class TextFieldExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TextField 예제'),
      ),
      body: TextField(
        decoration: InputDecoration(
          labelText: '이름',
          hintText: '이름을 입력하세요',
          border: OutlineInputBorder(), // 테두리 추가
        ),
        keyboardType: TextInputType.emailAddress, // 키보드 타입 설정, 텍스트 전용
        onChanged: (value) {
          print('입력한 값: $value');
        },
      ),
    );
  }
}

 

결과

  • 결과 화면

  • 선택했을 때(선택했을 때 키보드가 올라오지 않는다면 cmd + K)

 

속성

속성 설명
controller 입력된 데이터를 제어하는 컨트롤러
decoration 라벨, 힌트, 테두리 등 UI 설정
keyboardType 텍스트, 숫자, 이메일 등 키보드 타입 설정
obscureText true 설정 시 비밀번호처럼 입력 내용을 숨김
maxLength 최대 입력 길이 설정
onChanged 사용자가 입력할 때마다 호출되는 콜백 함수
onSubmitted 키보드의 완료(Enter) 버튼을 눌렀을 때 실행
focusNode 포커스 제어를 위한 노드
autofocus 화면에 진입했을 때 자동으로 포커스 설정
enabled false 설정 시 입력 불가능 (비활성화)

 


TextFormField

특징

  • TextField의 확장 버전으로 폼 검증과 유효성 검사 기능이 추가된 위젯
  • 유효성 검사, 자동 저장, 포커스 관리 등 폼 제출과 관련된 기능을 제공(ex. 회원가입, 로그인 등)

예제코드

import 'package:flutter/material.dart';

class FormExample extends StatefulWidget {
  @override
  State<FormExample> createState() => _FormExampleState();
}

class _FormExampleState extends State<FormExample> {
  final _formKey = GlobalKey<FormState>(); // Form의 key
  final TextEditingController _controller = TextEditingController();
  String? _name;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('TextFormField 예제')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey, // 폼의 고유 키 (필수)
          child: Column(
            children: [
              TextFormField(
                controller: _controller,
                decoration: InputDecoration(labelText: '이름'),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return '이름을 입력하세요';
                  }
                  return null;
                },
                onSaved: (value) => _name = value, // .save() 호출 시 저장
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  if (_formKey.currentState!.validate()) {
                    _formKey.currentState!.save(); // 모든 onSaved() 실행
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('입력한 이름: $_name')),
                    );
                  }
                },
                child: Text('제출'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
  • Form 위젯 : TextFormField를 감싸며, GlobalKey<FormState>를 통해 폼 상태 관리
  • validator 속성 : 유효성 검사를 위한 로직(입력된 값이 없으면 '이름을 입력하세요' 호출, 값이 입력되어 null 반환 시 성공 로직)
  • onSaved 속성: .save() 호출 시 value 값이 _name에 저장
  • _formKey.currentState!.validate() : 모든 validator 검사를 실행
  • _formKey.currentState!.save(): onSaved 메서드 실행

 

결과

  • value의 값이 비어있을 때 (즉, 입력된 값이 없을 때)

  • 값이 입력됐을 때(유효성 검사 통과)

 

속성

속성 설명 예시
controller TextField와 동일하게 텍스트 제어 controller: _controller
validator 유효성 검사 로직을 정의 validator: (value) => value!.isEmpty ? '필수 입력' : null
onSaved Form에서 .save() 호출 시 실행 onSaved: (value) => _name = value
autovalidateMode 입력 시 자동으로 유효성 검사 수행 autovalidateMode: AutovalidateMode.onUserInteraction
keyboardType 키보드 타입 설정 (예: 숫자, 이메일 등) keyboardType: TextInputType.emailAddress
obscureText 비밀번호 입력을 위한 텍스트 숨김 obscureText: true
maxLength 최대 글자 수 제한 maxLength: 20

TextEditingController

특징

  • TextField 또는 TextFormField의 텍스트를 제어하고 관리하는 컨트롤러
  • 초기값 설정, 텍스트 변경 감지, 텍스트 동적 업데이트, 텍스트 값 가져오기 및 수정 등의 기능을 함.

 

예제코드

  • TextEditingController는 생성 후 반드시 dispose()를 호출하여 메모리 누수를 방지해야함.
import 'package:flutter/material.dart';

class TextEditingControllerExample extends StatefulWidget {
  @override
  State<TextEditingControllerExample> createState() =>
      _TextEditingControllerExampleState();
}

class _TextEditingControllerExampleState
    extends State<TextEditingControllerExample> {
  final TextEditingController _controller = TextEditingController();

  @override
  void dispose() {
    _controller.dispose(); // 메모리 누수 방지
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('TextEditingController 예제')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                labelText: '이름을 입력하세요',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // 입력한 값 가져오기
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('입력한 이름: ${_controller.text}')),
                );
              },
              child: Text('입력한 값 확인'),
            ),
          ],
        ),
      ),
    );
  }
}

 

 

결과

  • TextField 클릭 전

  • TextField 클릭 후

  • 값 입력 후 제출 화면

 

속성

속성 설명 예시
text 현재 TextField에 입력된 텍스트를 가져오거나 설정 _controller.text = '안녕하세요';
value TextEditingValue 객체로 커서 위치, 선택 범위까지 포함된 전체 상태 관리 _controller.value = TextEditingValue(text: '텍스트', selection: TextSelection.collapsed(offset: 3));
selection 커서 위치 및 선택 범위를 설정 (텍스트 선택 제어) _controller.selection = TextSelection(baseOffset: 0, extentOffset: 5);
clear() 입력된 텍스트를 지우는 메서드 (속성 아님) _controller.clear();
addListener() 값이 변경될 때 호출되는 리스너 추가 _controller.addListener(() => print(_controller.text));
dispose() 메모리 누수를 방지하는 메서드 (위젯 종료 시 필수) _controller.dispose();