TextField

박동규·2023년 11월 22일
0

Widgets

목록 보기
12/18
post-thumbnail

TextField

  • 기본 설명: TextField는 간단한 텍스트 입력 필드로, 사용자가 텍스트를 입력할 수 있는 기본적인 UI 컴포넌트입니다.
  • 특징:
    • 단독으로 사용될 수 있으며, 양식(Form)과 관련된 추가 기능 없이 텍스트 입력을 처리합니다.
    • 컨트롤러(TextEditingController), 스타일링, 입력 형식 지정(TextInputType), 장식(InputDecoration) 등의 기본적인 텍스트 입력 기능을 제공합니다.

전체코드

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

class UsernameScreen extends StatefulWidget {
  const UsernameScreen({super.key});

  
  State<UsernameScreen> createState() => _UsernameScreenState();
}

class _UsernameScreenState extends State<UsernameScreen> {
  final TextEditingController _usernameController = TextEditingController();

  String _username = '';

  
  void initState() {
    super.initState();
    _usernameController.addListener(() {
      setState(() {
        _username = _usernameController.text;
      });
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Sign up',
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: Sizes.size36),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Gaps.v40,
            const Text(
              'Create username',
              style: TextStyle(
                fontSize: Sizes.size24,
                fontWeight: FontWeight.w700,
              ),
            ),
            Gaps.v8,
            const Text(
              'You can always change it later.',
              style: TextStyle(
                fontSize: Sizes.size16,
                color: Colors.black54,
              ),
            ),
            Gaps.v16,
            TextField(
              controller: _usernameController,
              cursorColor: Theme.of(context).primaryColor,
              decoration: InputDecoration(
                hintText: 'Username',
                enabledBorder: UnderlineInputBorder(
                  borderSide: BorderSide(
                    color: Colors.grey.shade400,
                  ),
                ),
                focusedBorder: UnderlineInputBorder(
                  borderSide: BorderSide(
                    color: Colors.grey.shade400,
                  ),
                ),
              ),
            ),
            Gaps.v16,
            FractionallySizedBox(
              widthFactor: 1,
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 300),
                padding: const EdgeInsets.symmetric(vertical: Sizes.size16),
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(Sizes.size5),
                  color: _username.isEmpty
                      ? Colors.grey.shade300
                      : Theme.of(context).primaryColor,
                ),
                child: const Text(
                  'Next',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: Sizes.size16,
                    fontWeight: FontWeight.w600,
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

TextField Widget을 사용하기 위해서는 Stateful Widget에서 Controller를 멤버 변수로 선언해야한다.

class _UsernameScreenState extends State<UsernameScreen> {
  final TextEditingController _usernameController = TextEditingController();

  String _username = '';

  
  void initState() {
    super.initState();
    _usernameController.addListener(() {
      setState(() {
        _username = _usernameController.text;
      });
    });
  }

다음과 같이 _usernameControllerTextEditingController()로 선언한 후 [[GDSC스터디/initState]]를 통해 addListener로 setState를 정의해준다.

FractionallySizedBox(
  widthFactor: 1,
  child: AnimatedContainer(
    duration: const Duration(milliseconds: 300),
    padding: const EdgeInsets.symmetric(vertical: Sizes.size16),
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(Sizes.size5),
      color: _username.isEmpty
          ? Colors.grey.shade300
          : Theme.of(context).primaryColor,
    ),
    child: const Text(
      'Next',
      textAlign: TextAlign.center,
      style: TextStyle(
        color: Colors.white,
        fontSize: Sizes.size16,
        fontWeight: FontWeight.w600,
      ),
    ),
  ),
)
final TextEditingController _emailController = TextEditingController();

  String _email = '';

  String? _isEmailValid() {
    if (_email.isEmpty) return 'Not valid';
    final regExp = RegExp(
        r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+");
    if (!regExp.hasMatch(_email)) return 'Email not valid';
    return null;
  }

  void _onScaffoldTap() {
    FocusScope.of(context).unfocus();
  }

  void _onSubmit() {
    if (_email.isEmpty || _isEmailValid() != null) return;
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => const PasswordScreen(),
      ),
    );
  }

    TextField(
        onEditingComplete: _onSubmit,
        autocorrect: false,
        keyboardType: TextInputType.emailAddress,
        controller: _emailController,
        cursorColor: Theme.of(context).primaryColor,
        decoration: InputDecoration(
          hintText: 'Email',
          enabledBorder: UnderlineInputBorder(
            borderSide: BorderSide(
              color: Colors.grey.shade400,
            ),
          ),
          focusedBorder: UnderlineInputBorder(
            borderSide: BorderSide(
              color: Colors.grey.shade400,
            ),
          ),
          errorText: _isEmailValid(),
        ),
      ),
  • onEditingComplete
    사용자가 키패드에서 done버튼을 누르면 콜백함수 실행
    void Function()? onEditingComplete
  • autocorrect
    자동완성 기능
    bool
  • keyboardType
    키보드의 타입을 바꿀 수 있다.
    TextInputType? keyboardType
  • errorText
    에러 메세지를 보여줄 수 있다.
    String? errorTex
  • enabled
    textfield를 눌렀을 때 활성화되는 것을 설정할 수 있다.
prefixIcon: const Icon(Icons.ac_unit),
suffixIcon: const Icon(Icons.ac_unit),

다음과 같이 InputDecoration 내부에서 설정할 수 있다.

textfield 앞 뒤로 아이콘을 넣을 수 있다.
icon만이 아닌 위젯을 넣고 싶다면 prefix, suffix parameter를 사용하면 된다.

suffix: const Row(
    children: [
      FaIcon(FontAwesomeIcons.circleXmark),
      Gaps.h5,
      FaIcon(FontAwesomeIcons.eye),
    ],
  ),

다음과 같이 suffix를 설정하면 screen이 다음과 같이 된다.

그 이유는 Row는 최대한 많은 너비를 가지려는 성질이 있기 때문이다.
이를 해결하기 위해서는 Row()의 가로 길이인 MainAxisSize.min 을 설정해야한다.
[[Row & Column 공간 문제]]

Another Input Widget

하지만 한 화면에 입력칸이 두 개 이상이거나, 로그인 화면, 사용자 프로필 설정과 같은 화면에서는 강력한 유효성 검사가 중요하기 때문에 TextField 위젯이 아닌 다른 위젯을 사용한다.

profile
내가 원하는 것을 만들자

0개의 댓글