Flutter와 Firebase로 Android iOS 둘 다 만들기 16 form 작성해보기

2 분 소요

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’) 이 있다면 붉은 글씨로 텍스트폼필드 아래에 표시합니다.

영상

댓글남기기