새로운 강의는 이제 https://memi.dev 에서 진행합니다.
memi가 Vue & Firebase로 직접 만든 새로운 사이트를 소개합니다.
Flutter와 Firebase로 Android iOS 둘 다 만들기 16 form 작성해보기
TextFormInputField를 사용해서 입력부를 구현해봅니다.
개요
이메일 패스워드를 사용해서 회원가입을 할 경우 기본적으로 이메일 형식 검사와 패스워드 확인 절차정도는 기본입니다.
이미 잘 짜여져있는 플러터의 폼검사 기능을 이용해서 간단히 구현해봅니다.
방법
참고: https://flutter-ko.dev/docs/cookbook#forms
방법은 여러가지 있는데 그 중 몇가지 샘플을 만들어 보겠습니다.
onchange를 이용하기
class SignUp extends StatefulWidget {
SignUp({Key key}) : super(key: key);
@override
_SignUpState createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
String _text = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('SignUp')),
body: Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
TextFormField(
initialValue: '',
onChanged: (v) {
setState(() => _text = v);
},
),
RaisedButton(
child: Text('submit!'),
onPressed: () {
print(_text);
setState(() => _text = '');
},
)
],
),
),
);
}
}
인풋에 뭔가를 적을 때마다 _text라는 변수를 채우고 버튼을 누를 때 해당정보를 확인할 수 있습니다.
문제는 setState(() => _text = ‘’);로 의도한 대로 지워지지 않는 다는 것입니다.
이런 방법은 그래서 거의 안쓰일 것 같습니다.
사실 이 방법으로 앱을 배포하기도 했습니다.. 뭐 일단 돌아는 가니까요..
콘트롤러 사용하기
class _SignUpState extends State<SignUp> {
TextEditingController controller = TextEditingController(text: 'initValue');
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('SignUp')),
body: Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
TextFormField(
controller: controller,
onChanged: (v) => print('onChanged $v'),
),
RaisedButton(
child: Text('submit!'),
onPressed: () {
print(controller.text);
controller.clear();
},
),
],
),
),
);
}
}
콘트롤러를 사용해서 위와 똑같은 동작을 하게 만들었습니다.
초기값을 줄 수도 있으며 값을 취하기도, 값을 클리어하기도 간단해집니다.
선언이 귀찮지만 결국 콘트롤러를 사용하는 것이 훨씬 편리한 것을 알 수 있습니다.
콘트롤러 리스너
위의 코드의 onChanged에서 입력값을 볼 수도 있지만 리스너를 둘 수도 있습니다.
@override
void initState() {
controller.addListener(() => print('addListener: ${controller.text}'));
super.initState();
}
큰 의미는 없지만 아래 코드를 설명하기 위해서 구현해본 것입니다.
콘트롤러 해제
리스너가 있다는 것은 콘트롤러를 생성했다면 해제해주는 것을 잊지 말아야한다는 것입니다.
addListener를 지정하던 안하던 해제해주는 것이 좋습니다.
@override
void dispose() {
controller.dispose();
super.dispose();
}
statuful widget에 들어올 때 initState라면 나갈 때 dispose라는 곳에 들리게 할 수 있습니다. 이때 제거하면 됩니다.
폼검사하기
이메일이 비어있거나 규칙이 맞지 않을 때 유효성 판단할 수 있는 방법을 제공합니다.
필요한 것은 3가지 입니다.
- Form
- key
- Validator
class _SignUpState extends State<SignUp> {
TextEditingController controller = TextEditingController(text: '');
final _formKey = GlobalKey<FormState>();
@override
void initState() {
controller.addListener(() => print('addListener: ${controller.text}'));
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
_buildForm () {
return Form(
key: _formKey,
child: Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
TextFormField(
controller: controller,
validator: (v) {
if (v.isEmpty) return 'bad';
return null;
},
),
RaisedButton(
child: Text('submit!'),
onPressed: () {
if (!_formKey.currentState.validate()) return;
print(controller.text);
controller.clear();
},
)
],
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('SignUp')),
body: _buildForm(),
);
}
}
Form으로 감싸면 코드가 길어져서 _buildForm()으로 정리했습니다.
_formKey.currentState.validate()를 호출하면 TextFormField에 있는 validator가 작동합니다.
validator는 현재 값을 인자로 주고 반환 값(return ‘bad’) 이 있다면 붉은 글씨로 텍스트폼필드 아래에 표시합니다.
댓글남기기