Frontend/Flutter
[Flutter] TextFormField를 사용하여 textfield 상태관리 하기
김룹
2024. 2. 21. 10:14
유효성을 검사할 수 있는 옵션이 존재하는가?
=> Form 기능 + TextField 기능 = TextFormField
Form위젯 사용하여 textField 상태관리 하는 방법
플러터에서 TextField를 입력 받으려면 기본적으로 TextEditingController를 사용해야 한다.
TextField가 하나라면 괜찮지만 많아질수록 컨트롤러 관리가 어려워진다 @_@
하지만 TextFormField를 사용하면 쉽게 validation과 값을 받아올 수 있음 !
기본 레이아웃
import 'package:flutter/material.dart';
class FormScreen extends StatefulWidget {
@override
_FormScreenState createState() => _FormScreenState();
}
class _FormScreenState extends State<FormScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// 여기에 폼 작성하기
],
),
);
}
}
Form 위젯 사용하기
final formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return DefaultAppbarLayout(
child: Form(
key: this.formKey,
child: Column(
children: [
// 여기에 TextFormField들 입력하기!
],
),
),
);
}
✔️ Form 위젯은 child와 key 파라미터를 받는다.
- child에는 TextFormField들을 넣어준다
- key에는 GlobalKey를 넣어주면 됨! 이 key는 나중에 폼 내부의 TextFormField 값들을 저장하고 validation을 진행하는데 사용된다.
TextFormField 위젯 생성 함수
renderTextFormField({
@required String label,
@required FormFieldSetter onSaved,
@required FormFieldValidator validator,
}) {
assert(onSaved != null);
assert(validator != null);
return Column(
children: [
Row(
children: [
Text(
label,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w700,
),
),
],
),
TextFormField(
onSaved: onSaved,
validator: validator,
),
],
);
}
TextFormField의 onSaved, validator 파라미터
@override
Widget build(BuildContext context) {
return DefaultAppbarLayout(
child: Form(
key: this.formKey,
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
renderTextFormField(
label: '이름',
onSaved: (val) {},
validator: (val) {
return null;
},
),
renderTextFormField(
label: '이메일',
onSaved: (val) {},
validator: (val) {
return null;
},
),
renderTextFormField(
label: '비밀번호',
onSaved: (val) {},
validator: (val) {
return null;
},
),
renderTextFormField(
label: '주소',
onSaved: (val) {},
validator: (val) {
return null;
},
),
renderTextFormField(
label: '닉네임',
onSaved: (val) {},
validator: (val) {
return null;
},
),
],
),
),
),
);
}
✔️ TextFormField는 onSaved와 validator 파라미터를 받는다.
- onSaved의 시그니처는 FormFieldSetter 라는 typedef
- validator의 시그니처는 FormFieldValidator
- 둘 다 String을 받고 있고, validator는 String의 리턴값 또한 받는다. 리턴되는 String은 에러메시지로 사용된다
폼 저장 버튼 생성
renderButton() {
return RaisedButton(
color: Colors.blue,
onPressed: () {},
child: Text(
'저장하기!',
style: TextStyle(
color: Colors.white,
),
),
);
}
폼 저장 후 Snackbar 보여주기
renderButton() {
return RaisedButton(
color: Colors.blue,
onPressed: () async {
if(this.formKey.currentState.validate()){
// validation 이 성공하면 true 리턴!
// validation 이 성공하면 폼 저장하기
this.formKey.currentState.save();
Get.snackbar(
'저장완료!',
'폼 저장이 완료되었습니다!',
backgroundColor: Colors.white,
);
}
},
child: Text(
'저장하기!',
style: TextStyle(
color: Colors.white,
),
),
);
}
✔️ formKey.currentState.validate() 함수를 실행하면 Form 내부에 있는 TextFormField들의 validation 결과에 따라 성공이면 true 리턴, 실패하면 false 리턴해준다.
Validator 파라미터 작성
⚠️ TextField에 아무것도 입력하지 않아도 저장이 된다. 모든 TextField의 validation 파라미터를 return null로 저장해서 그렇다. TextField 별로 적절한 에러 메시지 작성하기!
@override
Widget build(BuildContext context) {
return DefaultAppbarLayout(
child: Form(
key: this.formKey,
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
renderTextFormField(
label: '이름',
onSaved: (val) {},
validator: (val) {
if(val.length < 1) {
return '이름은 필수사항입니다.';
}
if(val.length < 2) {
return '이름은 두글자 이상 입력 해주셔야합니다.';
}
return null;
},
),
renderTextFormField(
label: '이메일',
onSaved: (val) {
},
validator: (val) {
if(val.length < 1) {
return '이메일은 필수사항입니다.';
}
if(!RegExp(
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
.hasMatch(val)){
return '잘못된 이메일 형식입니다.';
}
return null;
},
),
renderTextFormField(
label: '비밀번호',
onSaved: (val) {},
validator: (val) {
if(val.length < 1) {
return '비밀번호는 필수사항입니다.';
}
if(val.length < 8){
return '8자 이상 입력해주세요!';
}
return null;
},
),
renderTextFormField(
label: '주소',
onSaved: (val) {},
validator: (val) {
if(val.length < 1) {
return '주소는 필수사항입니다.';
}
return null;
},
),
renderTextFormField(
label: '닉네임',
onSaved: (val) {},
validator: (val) {
if(val.length < 1) {
return '닉네임은 필수사항입니다.';
}
if(val.length < 8) {
return '닉네임은 8자 이상 입력해주세요!';
}
return null;
},
),
renderButton(),
],
),
),
),
);
}
onSaved 파라미터 작성하기
final formKey = GlobalKey<FormState>();
String name = '';
String email = '';
String password = '';
String address = '';
String nickname = '';
@override
Widget build(BuildContext context) {
return DefaultAppbarLayout(
child: Form(
key: this.formKey,
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
renderTextFormField(
label: '이름',
onSaved: (val) {
setState(() {
this.name = val;
});
},
validator: (val) {
if(val.length < 1) {
return '이름은 필수사항입니다.';
}
if(val.length < 2) {
return '이름은 두글자 이상 입력 해주셔야합니다.';
}
return null;
},
),
renderTextFormField(
label: '이메일',
onSaved: (val) {
setState(() {
this.email = val;
});
},
validator: (val) {
if(val.length < 1) {
return '이메일은 필수사항입니다.';
}
if(!RegExp(
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
.hasMatch(val)){
return '잘못된 이메일 형식입니다.';
}
return null;
},
),
renderTextFormField(
label: '비밀번호',
onSaved: (val) {
setState(() {
this.password = val;
});
},
validator: (val) {
if(val.length < 1) {
return '비밀번호는 필수사항입니다.';
}
if(val.length < 8){
return '8자 이상 입력해주세요!';
}
return null;
},
),
renderTextFormField(
label: '주소',
onSaved: (val) {
setState(() {
this.address = val;
});
},
validator: (val) {
if(val.length < 1) {
return '주소는 필수사항입니다.';
}
return null;
},
),
renderTextFormField(
label: '닉네임',
onSaved: (val) {
setState(() {
this.nickname = val;
});
},
validator: (val) {
if(val.length < 1) {
return '닉네임은 필수사항입니다.';
}
if(val.length < 8) {
return '닉네임은 8자 이상 입력해주세요!';
}
return null;
},
),
renderButton(),
],
),
),
),
);
}
✔️ 값을 받아보기 위해 onSaved 파라미터에서 저장 시 위젯의 변수에 값을 저장하는 기능 작성!
💡 꿀팁 !
- TextFormField에 autovalidateMode를 AutovalidateMode.always로 지정하면, 저장하기 버튼을 누르기 전에 각 TextFormField가 자동으로 validation을 진행하는 것을 볼 수 있다!
🌐 참고 링크