[플러터] 11. 페이지 이동, TextFormField

KangHo Lee's avatar
Dec 26, 2024
[플러터] 11. 페이지 이동, TextFormField

1. 페이지 이동

void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( // 최초 페이지 설정 initialRoute: "/login", // 페이지 이동 설정 routes: { "/login": (context) => LoginPage(), "/home": (context) => HomePage(), }, ); } }
  • MaterialApp 설정
    • initialRoute : 앱 실행 시 제일 먼저 보이는 화면 설정
    • routes: 페이지 이동 경로 설정
// stle 입력 후 자동 완성 class LoginPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("LoginPage")), body: Align( alignment: Alignment(0, 0), // double 가능 -> 소숫점으로 위치 설정 가능 child: ElevatedButton( onPressed: () { Navigator.pushNamed(context, "/home"); }, child: Text("로그인"), ), ), ); } }
  • Align
    • 위젯의 위치를 자유롭게 설정 가능
    • alignment
      • Alignment(-1, -1): 화면 제일 왼쪽 위
      • Alignment(0, 0): 중앙
      • Alignment(1, 1): 제일 오른쪽 아래
      • double로 설정 가능
  • Navigator.pushNamed(context, "/home")
    • 경로 /home 으로 이동
    • 이동할 경우 왼쪽 위에 뒤로 가기 버튼 자동 생성
// stle 입력 후 자동 완성 class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("HomePage")), body: Align( alignment: Alignment(0, 0), // (-1, -1) ~ (1, 1) child: ElevatedButton( onPressed: () { Navigator.pop(context); }, child: Text("돌아가기"), ), ), ); } }
  • Navigator.pop(context)
    • 현재 화면을 닫고 이전 화면으로 되돌아 갑니다.
💡
  • Flutter의 네비게이션 시스템에서 화면을 스택(stack)으로 관리합니다.
  • pop 메서드는 현재 스택의 맨 위에 있는 화면을 제거하고, 그 아래에 있는 화면을 표시하게 됩니다.

2. 문자 입력 시 올라오는 키보드가 버튼 가리지 않게 설정

import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( home: LoginPage(), ); } } class LoginPage extends StatelessWidget { const LoginPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: true, body: Column( children: [ Flexible( child: ListView( shrinkWrap: true, children: [ Container( height: 400, color: Colors.redAccent, ), TextFormField(), TextFormField(), TextFormField(), ], ), ), ElevatedButton(onPressed: () {}, child: Text("로그인")) ], ), ); } }
  • resizeToAvoidBottomInset
    • 키보드가 나타날 때 화면의 레이아웃이 어떻게 조정될지를 제어합니다.
    • true로 설정할 경우 키보드가 나타날 때 Scaffold의 body가 자동으로 크기를 조정하여 키보드에 의해 가려지지 않도록 합니다.
  • shrinkWrap: true
    • ListView의 세로 길이 설정
    • 스크롤 가능한 위젯이 자식 위젯의 크기에 따라 축소됩니다.
    • 스크롤 가능한 부모 위젯 안에서 자식 위젯이 공간을 낭비하지 않도록 도와줍니다.
  • Flexible 위젯
    • Row, Column, 또는 Flex 컨테이너의 자식 위젯으로, 자식이 main axis에 따라 유연하게 확장되도록 합니다.
  • TextFormField
    • 사용자 입력을 위한 필드입니다.
  • ElevatedButton을 ListView 아래에 위치시킬 경우 키보드가 올라와도 버튼이 가려지지 않습니다.
notion image
notion image
  • 키보드가 나타나면 로그인 버튼이 위로 올라간 것을 볼 수 있습니다.

3. 사용자가 입력한 값을 전송

class LoginPage extends StatelessWidget { LoginPage({super.key}); String? username; final password = TextEditingController(); final email = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: true, body: ListView( children: [ Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( onChanged: (value) { username = value; }, decoration: InputDecoration( filled: true, fillColor: Colors.yellow, // 배경색 설정 border: OutlineInputBorder( // 외곽선 설정 (옵션) borderRadius: BorderRadius.circular(12.0), ), ), ), ), CustomInput(password, "패스워드를 입력하세요", obsecure: true), CustomInput(email, "이메일을 입력하세요"), ElevatedButton( onPressed: () { fetch(username!.trim(), password.text.trim()); }, child: Text("로그인"), ), ], ), ], ), ); } }
  • TextFormField
    • onChanged: 입력값에 변화가 있을 경우 실행됩니다.
    • value: 입력값
    • fillColor: 배경색 설정
      • filled: true → 배경색을 채워줍니다.
    • border: OutlineInputBorder: 외곽선 설정
      • borderRadius → 외곽선을 둥글게 합니다.
  • username!.trim()
    • ! 연산자는 null이 아님을 보장합니다. → Dart는 해당 변수가 null이 아님을 인식하고, null safety 경고를 무시하게 됩니다.
  • trim()
    • 문자열의 앞뒤 공백을 제거합니다.
class CustomInput extends StatelessWidget { CustomInput(this.controller, this.hint, {this.obsecure = false}); final controller; final hint; final obsecure; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( controller: controller, obscureText: obsecure, decoration: InputDecoration( hintText: "${hint}", suffixIcon: Icon(Icons.password), focusedBorder: OutlineInputBorder(), enabledBorder: OutlineInputBorder(), ), ), ); } } void fetch(String username, String password) { print("$username$password를 전송하였습니다"); }
  • controller → TextEditingController에 담긴 값에 접근할 수 있습니다.
  • obscureText: true
    • 비밀번호를 알아 볼 수 없는 문자로 바꿔줍니다.
  • hintText
    • TextFormField에 힌트 텍스트를 설정할 수 있습니다.
  • suffixIcon: Icon(Icons.password)
    • TextFormField 제일 끝에 패스워드 아이콘을 넣습니다.
    • prefixIcon: 앞에 아이콘을 넣습니다.
  • focusedBorder
    • 입력 필드가 포커스를 받았을 때의 테두리 스타일을 정의합니다.
    • 사용자가 입력 필드에 터치하거나 클릭하여 텍스트를 입력할 때 활성화됩니다.
  • enabledBorder
    • 입력 필드가 활성화되었지만 포커스를 받지 않았을 때의 테두리 스타일을 정의합니다.
    • 입력 필드가 사용 가능한 상태일 때 기본적으로 표시되는 테두리 스타일입니다.
 
Share article

devleekangho