로그인 앱 만들기

gov's avatar
Dec 26, 2024
로그인 앱 만들기
💡
  1. 라우터 Router
  1. 사용자 입력 받기 -TextFormField / shrinkWrap
  1. 로그인 입력 화면 - Flexible / shrinkWrap / ListView

1. 라우터

1-1. 화면

notion image
notion image

1-2. 개념

  1. Named Routes 방식 MaterialApproutes 속성에 경로 이름(/login, /home)과 해당 경로에 연결된 위젯을 매핑하여 사용. Navigator.pushNamed()를 사용해 화면을 전환한다.
  1. initialRoute 초기 경로 설정 앱 시작시 보여지는 초기 화면을 설정. /login 경로와 연결된 LoginPage가 나온다.
  1. 화면 전환 구현
      • Navigator.pushNamed(context, "/home"); 화면 이동. 이름이 등록된 경로로 이동하며, 화면 스택에 새로운 화면을 추가.
      • Navigator.pop(context); : 뒤로 가기 현재 화면을 제거하고 이전 화면으로 돌아가기

1-3. 코드

import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( // 라우터 -버튼 누르면 화면 이동 initialRoute: "/login", // 초기화면 설정 routes: { "/login": (context) => LoginPage(), "/home": (context) => HomePage(), }, ); } } class LoginPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("LoginPage")), // Align 위치 지정가능 body: Align( alignment: Alignment(0, 0), // -1, -1 -> 1, 1 묵시적 형변환 child: ElevatedButton( onPressed: () { Navigator.pushNamed(context, "/home"); // 경로를 직접 설정하고 데이터를 전달할 수 있는 익명 라우팅 방식 // Navigator.push(context, MaterialPageRoute(builder: (context) => HomePage())); }, child: Text("로그인")), ), ); } } class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("HomePage")), body: Align( alignment: Alignment(0, 0), child: ElevatedButton( onPressed: () { Navigator.pop(context); }, child: Text("돌아가기")), ), ); } }

2. 사용자 입력받기

TextFormField는 사용자로부터 입력값을 수집하는 입력 필드.
여러 입력 항목(예: Username, Password, Email)을 화면에 배치할 때, 스크롤 가능하도록 ListView를 사용하기.

2-1. 화면

notion image

2-2. 개념

  1. TextFormField
      • 사용자 입력을 받기 위해 사용되는 위젯
      • 폼 입력을 쉽게 검증하고 관리가능하게 Form과 함께 사용
      • 텍스트 입력 필드의 상위 버전으로, 입력 검증 및 상태 관리 기능이 추가
  1. ListViewshrinkWrap
      • ListView는 기본적으로 스크롤 가능한 영역의 최대 크기(스크롤 가능한 부모 위젯 전체)를 차지한다.
      • shrinkWrap: true를 설정 시 ListView가 자식들의 크기만큼만 공간을 차지하도록 제한된다.

2-3. 코드

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( // ListView 크기를 조정하여 화면의 남은 공간을 사용 child: ListView( shrinkWrap: true, // 자식 요소 만큼 크기 축소 children: [ Container( height: 400, color: Colors.redAccent, ), TextFormField(), TextFormField(), TextFormField(), ], ), ), ElevatedButton(onPressed: () {}, child: Text("로그인")) ], ), ); } }

3. 로그인 입력 화면

3-1. 화면

notion image

3-2. 개념

  1. Flexible
      • 코드에 사용되지 않음
      • Column 이나 Row 안 위젯의 크기를 유동적으로 조정할 때 사용.
      • 부모 위젯의 남은 공간을 비율에 따라 나누어 사용하는 위젯.
      • 비슷한 위젯: Expanded 남은 공간을 모두 차지.
  1. shrinkWrap
      • 리스트뷰가 자식 요소만큼만 크기를 차지하도록 제어.
      • 스크롤 컨텍스트 내부에 중첩된 ListView에 유용.
  1. ListView
    1. 특징
        • 스크롤 가능한 위젯으로, 자식 위젯들을 세로 또는 가로 방향으로 나열.
        • 자식 위젯을 배열하거나 레이아웃을 구성할 때 사용.
    2. 적용
        • 로그인 화면의 전체 내용을 감싸는 주요 컨테이너로 사용.
        • LoginPage 화면에서 모든 입력 필드와 버튼을 스크롤 가능하도록 감쌈.
        • 여러 위젯을 스크롤 가능한 리스트 형태로 배치.

3-3. 코드

import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: LoginPage(), ); } } 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("로그인"), ), ], ), ], ), ); } } 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를 전송하였습니다"); }
💡

흐름 분석

  1. ListView
      • 로그인 화면의 전체를 감싸며 스크롤 가능한 화면을 구현.
      • shrinkWrap 사용해 크기를 자식 위젯만큼만 축소가능.
  1. Column
      • 입력 필드(TextFormField)와 버튼을 세로 나열.
      • Column 안에 개별적으로 패딩을 추가해 위젯 간 여백 조정.
  1. CustomInput
      • TextFormField를 커스터마이즈하여 반복되는 입력 필드 코드 간소화.
      • controller로 입력 데이터를 관리하고, 입력값을 가져오는 방식 사용.
  1. fetch 함수
      • 버튼 클릭 시 입력된 데이터를 콘솔로 출력하는 동작 구현.
Share article

goho