Form 위젯

 

목차

    1. Form 위젯

    • TextField는 단순히 하나의 텍스트 입력을 다루는데 반해서, Form은 그 자체로 입력 필드를 가지고 있지 않지만, FormField 위젯들을 그룹화하여 관리하며, 복잡한 유효성 검사와 보다 쉽게 할 수 있는 위젯이다
    • 다른 위젯과 달리 Form 위젯은 자체적인 화면을 제공하지는 않으며, 사용자가 입력한 데이터의 유효성 검증, 데이터 관리 관련 기능을 제공한다
    • Form 위젯 내에서 TextFormField 위젯을 사용하여 각 데이터 입력을 받는 것이 일반적이다

    Form 위젯 작성 방법은 다음과 같다

     

    1. Form 위젯을 위한 GlobalKey를 만들어야 한다.
    GlobalKey는 FormState 전체에 액세스하는 데 사용되며, 이 객체는 폼 데이터의 유효성을 검사하고 저장하는 데 사용된다

    final _formKey = GlobalKey<FormState>();

     

    2. TextFormField 위젯들의 폼 컨트롤을 위젯을 Form 위젯으로 래핑하고, _formKey를 Form 위젯의 key 속성으로 설정한다.

    Form(
      key: _formKey,
      child: Column(
        children: [
          // 폼 컨트롤들
        ],
      ),
    );

     

    3. TextFormField 위젯 또는 다른 폼 컨트롤을 Form 위젯에 추가한다. 각 폼 컨트롤은 validator 함수와 선택적인 onSaved 함수를 가져야 한다

    • validator 함수는 사용자가 폼을 제출할 때 호출되며, 입력이 유효한지 확인한다.
    • 입력이 유효하지 않으면 validator는 오류 메시지를 포함하는 문자열을 반환해야 한다.
    • 입력이 유효하면 validator는 null을 반환해야 한다.
    • onSaved 함수는 폼이 저장될 때 호출되며 사용자가 입력한 값을 변수나 데이터 모델에 저장해야 한다.
    TextFormField(
      decoration: InputDecoration(
        labelText: 'Email',
      ),
      validator: (value) {
        if (value == null || value.isEmpty) {
          return '이메일을 입력하세요';
        }
        return null;
      },
      onSaved: (value) {
        _email = value;
      },
    ),

    4. 폼에 제출 버튼을 추가하고 폼 제출을 처리할 함수를 정의한다

    • _submitForm 함수는 FormState 객체의 validate 메서드(_formKey.currentState!.validate())를 사용하여 폼 유효성을 검사하고
    • FormState 객체의 save 메서드(_formKey.currentState!.save())를 사용하여 폼 데이터를 저장해야 함
    • _formKey.currentState!에서 _formKey는 GlobalKey 객체이고, 여기에서 currentState는 FormState 객체이다
      해당 객체가 없지 않다는 것을 명시적으로 알려주기 위해 !(Exclamation mark)를 기재한 것
    • 폼 데이터가 유효하면 _submitForm 함수는 데이터를 의도한대로 처리하게 된다
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp8());
    }
    
    class MyApp8 extends StatefulWidget {
      const MyApp8({super.key});
    
      @override
      State<MyApp8> createState() => _MyApp8State();
    } // end of class
    
    class _MyApp8State extends State<MyApp8> {
      // Form 위젯 만들어 보기
      final _formKey = GlobalKey<FormState>();
      String _name = '';
      String _email = '';
      String _password = '';
      String _errorMessage = '';
    
      // 멤버 함수 만들어보기
      void _submitForm() {
        print('_formKey.currentState!.validate() : ${_formKey.currentState!.validate()}');
        if(_formKey.currentState!.validate()) {
          // TextFormField --> validator 호출 --> 모두 통과 하면 true 를 반환 한다.
    
          // 다음단계 --> onSaved 메서드를 실행 시킨다.
          _formKey.currentState!.save(); // 각각에 formfield onSaved 메서드 호출 됨
          setState(() {
            _errorMessage = '';  // 상태 변경 처리
            // 변수안에 값 확인 -->
            print('_name : $_name');
            print('_email : $_email');
            print('_password : $_password');
    
            // 통신 요청
            //http.get(~);
            //http.post(~);
            // 응답 받아서 화면 이동 처리 , 메세지 던져 주기
    
          });
        } else {
          setState(() {
            _errorMessage = '필수값들을 입력하시오';
          });
        }
    
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Form Example'),
            ),
            body: Container(
              padding: const EdgeInsets.all(16.0),
              // form 위젯은 위젯들을 구분할 수 있는 키가 필요하다.
              child: Form(
                key: _formKey,
                child: Column(
                  children: [
                    TextFormField(
                      decoration: InputDecoration(
                        labelText: 'name',
                        errorStyle: TextStyle(color: Colors.blue, fontSize: 10),
                      ),
                      validator: (value) {
                        if (value == null || value.isEmpty) {
                          return '이름을 입력하세요';
                        }
                        return null;
                      },
                      // value 매개변수 값이 null 이 될 수 있다.
                      onSaved: (value) {
                        // value! 강제 null 아니라고 명시 함
                        _name = value!;
                      },
                    ),
                    TextFormField(
                      decoration: InputDecoration(
                        labelText: 'email',
                        errorStyle: TextStyle(color: Colors.blue, fontSize: 10),
                      ),
                      validator: (value) {
                        if (value == null || value.isEmpty) {
                          return '이메일을 입력하세요';
                        }
                        return null;
                      },
                      // value 매개변수 값이 null 이 될 수 있다.
                      onSaved: (value) {
                        // value! 강제 null 아니라고 명시 함
                        _email = value!;
                      },
                    ),
                    TextFormField(
                      decoration: InputDecoration(
                        labelText: 'password',
                        errorStyle: TextStyle(color: Colors.blue, fontSize: 10),
                      ),
                      validator: (value) {
                        if (value == null || value.isEmpty) {
                          return '비밀번호을 입력하세요';
                        }
                        return null;
                      },
                      // value 매개변수 값이 null 이 될 수 있다.
                      onSaved: (value) {
                        // value! 강제 null 아니라고 명시 함
                        _password = value!;
                      },
                    ),
                    const SizedBox(height: 20),
                    ElevatedButton(
                      onPressed: _submitForm, // 코드 축약
                      child: Text('Submit'),
                    ),
                    const SizedBox(height: 20),
                    Text(
                      _errorMessage,
                      style: TextStyle(color: Colors.red),
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    } // end of class

     

    2. GlobalKey란 무엇인가?

    GlobalKey는 Flutter에서 위젯 트리 내에서 특정 위젯을 유일하게 식별할 수 있는 키이다. 이 키를 사용하면 해당 위젯이나 그 상태(State)에 직접 접근하여 조작할 수 있다.

     

    상태(State)란?

    위젯이 현재 가지고 있는 데이터나 속성을 의미하며, 시간이 지남에 따라 변경될 수 있는 값이다.

     

    StatelessWidget VS StatefulWidget의 차이

     

    StatelessWidget

    • 정의: 상태를 가지지 않는 위젯이다. 내부에 데이터나 속성을 가질 수 있으나 내부에 변경 가능한 데이터나 속성이 없기 때문에 자체적으로 UI가 업데이트되지 않는다.
    • 하지만(추가 설명)
      • 외부로부터의 변화: StatelessWidget은 부모 위젯이나 외부에서 전달된 데이터가 변경되면 재빌드되어 UI가 업데이트될 수 있다.
      • 한정된 업데이트: 하지만 자체적으로 상태를 관리하거나 변경하지 않으므로, 내부적인 상태 변화로 인한 UI 업데이트는 발생하지 않는다.

    StatefulWidget

    • 정의: 상태(State)를 가지는 위젯입니다. 시간이 지남에 따라 상태가 변경될 수 있고, 이에 따라 UI도 업데이트된다.
    • 추가 설명:
      • 상태 관리: StatefulWidget은 State 객체를 통해 상태를 관리하며, 상태가 변경될 때마다 setState() 메서드를 호출하여 UI를 갱신한다.
      • 독립성: 자체적으로 상태를 관리하기 때문에, 외부의 변화뿐만 아니라 내부적인 상태 변화에도 대응할 수 있다.

     

    GlobalKey의 주요 기능

    1. 위젯 식별: 동일한 타입의 위젯이 여러 개 있더라도, GlobalKey를 사용하면 특정 위젯을 구분할 수 있다.
    2. 상태 접근: StatefulWidget의 상태(State)에 직접 접근하여 값을 읽거나 변경할 수 있다.
    3. 위젯 위치 정보 얻기: 위젯의 위치나 크기 등의 정보를 얻어올 수 있다.

    목차로 돌아가기