개발노트

20. [Flutter] Form 여러 개가 입력된 데이터 유효성 검사하기(with GlobalKey) 본문

앱 개발/Flutter

20. [Flutter] Form 여러 개가 입력된 데이터 유효성 검사하기(with GlobalKey)

mroh1226 2023. 6. 27. 18:28
반응형

Form

Form 위젯은 데이터의 유효성을 검사하고 제출할 때 유용한 기능을 제공합니다. 이를 위해 Form 위젯 내부에서 GlobalKey<FormState>를 사용하여 폼의 상태를 관리하고 유효성 검사를 수행할 수 있습니다.


 

Form 위젯의 자식 위젯으로 사용되는 것들.

  • TextFormFeild
Form(
  child: Column(
    children: <Widget>[
      TextFormField(
        decoration: InputDecoration(
          labelText: 'Name',
        ),
        validator: (value) {
          if (value.isEmpty) {
            return 'Please enter your name.';
          }
          return null;
        },
      ),
      TextFormField(
        decoration: InputDecoration(
          labelText: 'Email',
        ),
        validator: (value) {
          if (value.isEmpty) {
            return 'Please enter your email.';
          }
          return null;
        },
      ),
      // 추가적인 입력 위젯들...
    ],
  ),
);

 

  • CheckBox
Form(
  child: Column(
    children: <Widget>[
      CheckboxListTile(
        title: Text('Agree to Terms'),
        value: _agreeToTerms,
        onChanged: (bool value) {
          setState(() {
            _agreeToTerms = value;
          });
        },
      ),
      // 추가적인 체크박스들...
    ],
  ),
);

 

  • RadioButton
Form(
  child: Column(
    children: <Widget>[
      RadioListTile(
        title: Text('Option 1'),
        value: 1,
        groupValue: _selectedOption,
        onChanged: (value) {
          setState(() {
            _selectedOption = value;
          });
        },
      ),
      RadioListTile(
        title: Text('Option 2'),
        value: 2,
        groupValue: _selectedOption,
        onChanged: (value) {
          setState(() {
            _selectedOption = value;
          });
        },
      ),
      // 추가적인 라디오 버튼들...
    ],
  ),
);

 

  • DropdownButton
Form(
  child: Column(
    children: <Widget>[
      DropdownButtonFormField<String>(
        value: _selectedOption,
        items: ['Option 1', 'Option 2', 'Option 3']
            .map((String value) {
          return DropdownMenuItem<String>(
            value: value,
            child: Text(value),
          );
        }).toList(),
        onChanged: (value) {
          setState(() {
            _selectedOption = value;
          });
        },
        decoration: InputDecoration(
          labelText: 'Select an option',
        ),
      ),
      // 추가적인 드롭다운 버튼들...
    ],
  ),
);

GlobalKey

GlobalKey<FormState>는 Form 위젯의 상태를 전역적으로 관리하는 키입니다.

Form의 key: 속성에 GlobalKey를 할당하면 해당 GlobalKey를 Form 위젯의 State와 메서드에 사용할 수 있습니다.

import 'package:flutter/material.dart';
import 'package:flutter_application_ticktok_clone/constants/gaps.dart';
import 'package:flutter_application_ticktok_clone/constants/sizes.dart';

enum Gneder { man, women }

class TestScreen extends StatefulWidget {
  const TestScreen({super.key});
  @override
  State<TestScreen> createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  Map<String, String> formData = {};
  late bool? _checked = false;
  Gneder? gneder = Gneder.man;
  final GlobalKey<FormState> _globalKey = GlobalKey<FormState>();
  void onTapBtn() {
    if (_globalKey.currentState == null) return;
    _globalKey.currentState!.validate();
    _globalKey.currentState!.save();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.symmetric(
            horizontal: Sizes.size28, vertical: Sizes.size36),
        child: Form(
          key: _globalKey,
          child: Column(children: [
            Gaps.v80,
            TextFormField(
              validator: (value) {
                if (value != null && value.isEmpty) {
                  return "Check Your Email Address.";
                }
                return null;
              },
              onSaved: (newValue) => formData['email'] = newValue.toString(),
              decoration: const InputDecoration(hintText: "Insert Your Email"),
            ),
            TextFormField(
              validator: (value) {
                if (value != null && value.isEmpty) {
                  return "Check Your Password.";
                }
                return null;
              },
              decoration: const InputDecoration(hintText: "Password"),
            ),
            SizedBox(
              width: 150,
              height: 50,
              child: CheckboxListTile(
                title: const Text('Agree?'),
                value: _checked,
                onChanged: (value) {
                  setState(() {
                    _checked = value;
                  });
                },
              ),
            ),
            Row(
              children: [
                SizedBox(
                  width: 150,
                  child: RadioListTile(
                    title: const Text('Man'),
                    value: Gneder.man,
                    groupValue: gneder,
                    onChanged: (value) {
                      setState(() {
                        gneder = value;
                      });
                    },
                  ),
                ),
                SizedBox(
                  width: 150,
                  child: RadioListTile(
                    title: const Text('Women'),
                    value: Gneder.women,
                    groupValue: gneder,
                    onChanged: (value) {
                      setState(() {
                        gneder = value;
                      });
                    },
                  ),
                ),
              ],
            ),
            GestureDetector(
              onTap: () => onTapBtn(),
              child: Container(
                  padding:
                      const EdgeInsets.symmetric(horizontal: 100, vertical: 20),
                  decoration: const BoxDecoration(color: Colors.amber),
                  child: const Text('Button')),
            ),
          ]),
        ),
      ),
    );
  }
}
  • void _onSubmitTap() {
    if (_formKey.currentState != null)
      {     if (_formKey.currentState!.validate())
        {     _formKey.currentState!.save(); } } }

    첫 번째 조건문 if (_formKey.currentState != null)은 현재 상태가 null이 아닌지 확인합니다. 이는 폼 위젯이 초기화되었는지 확인하기 위함입니다. null인 경우에는 폼이 아직 생성되지 않았거나 폼 위젯의 키가 잘못 설정되었을 수 있습니다.

    두 번째 조건문 if (_formKey.currentState!.validate())은 _formKey의 현재 상태의 유효성 검사를 수행합니다. validate() 함수는 폼 위젯의 각 입력 필드에 설정된 유효성 검사 함수(validator)를 호출하고, 모든 필드가 유효한지 여부를 반환합니다. 필드의 값이 유효하지 않은 경우 해당 필드에 오류 메시지가 표시됩니다. 모든 필드가 유효한 경우 true를 반환하고, 그렇지 않은 경우 false를 반환합니다.

    유효성 검사를 통과한 경우, _formKey.currentState!.save() 함수가 호출됩니다. 이는 각 TextFormField의 onSaved 콜백을 실행하여 입력값을 저장합니다. onSaved 콜백은 이전에 설명한대로 formData 맵 또는 다른 데이터 저장 방식을 사용하여 입력값을 저장합니다.

    함수의 나머지 부분은 주석 처리되어 있으므로 현재로서는 실행되지 않습니다. 하지만 주석 처리된 코드인 _formKey.currentState?.validate()은 Optional Chaining 연산자를 사용하여 동일한 유효성 검사를 실행합니다. 이는 null일 경우에도 안전하게 실행할 수 있도록 도와줍니다.

    요약하자면, _onSubmitTap 함수는 폼 제출 시 폼의 유효성을 검사하고, 유효성 검사를 통과한 경우 입력값을 저장하는 역할을 수행합니다.

  • GlobalKey<FormState>:
    GlobalKey는 애플리케이션에서 특정 위젯에 대한 고유한 식별자 역할을 합니다. GlobalKey<FormState>는 Form 위젯에 연결된 키로, Form 위젯의 상태를 추적하고 조작할 수 있게 합니다.

  • TextFormField 
    - validator:
    각각의 위젯에는 validator 콜백이 있습니다. 이 콜백은 사용자 입력을 유효성 검사하는 데 사용됩니다. 입력이 유효하지 않으면 해당 콜백은 오류 메시지를 반환하고, 입력이 유효하면 null을 반환합니다.
    - onSaved:
    TextFormField 위젯의 onSaved 콜백은 사용자의 입력 값을 저장합니다. Form 위젯에 연결된 GlobalKey를 통해 save 메서드를 호출하면 onSaved 콜백이 실행되어 입력 값을 저장합니다.

  • CheckboxListTile:
    CheckboxListTile 위젯은 체크박스를 나타내며, 사용자가 선택한 값을 저장합니다. value 매개변수로 현재 체크 상태를 전달하고, onChanged 콜백을 통해 체크 상태 변경을 감지하고 상태를 업데이트합니다.

  • RadioListTile:
    RadioListTile 위젯은 라디오 버튼을 나타내며, 여러 개의 라디오 버튼 중 하나를 선택한 값을 저장합니다. value 매개변수로 현재 선택된 값과 groupValue를 전달하고, onChanged 콜백을 통해 선택된 값을 감지하고 상태를 업데이트합니다.

  • GestureDetector:
    GestureDetector 위젯은 터치 및 제스처 이벤트를 처리할 수 있는 위젯입니다. 여기서는 버튼으로 사용되며, onTap 콜백을 통해 버튼을 클릭할 때의 동작을 정의합니다.

  • setState():
    setState() 메서드는 StatefulWidget에서 상태를 변경할 때 사용됩니다. 해당 메서드를 호출하면 상태 변경을 알리고, Flutter는 변경된 상태에 따라 위젯을 다시 렌더링합니다.

    위의 예제에서는 Form 위젯과 GlobalKey<FormState>를 사용하여 사용자 입력을 관리하고 유효성을 검사합니다. TextFormField를 사용하여 사용자로부터 이메일과 패스워드를 입력받고, CheckboxListTile을 사용하여 동의 여부를 선택하고, RadioListTile을 사용하여 성별을 선택합니다. 마지막으로 GestureDetector를 사용하여 버튼을 클릭할 때 입력 값을 검증하고 저장합니다.



빌드된 모습

반응형
Comments