본문 바로가기
Frontend/Flutter

[flutter19] LoginApp 만들기

by JINJINC 2025. 1. 13.
728x90
반응형

 Login App 만들기 01- 구조 

 

1. form 태그 안에서  각각의 객체들은 

 

logo.svg

 

 

앱의 진입점

 

라우터 명령어를 사용해 전환하여 사용

import 'package:flutter/material.dart';
import 'package:flutter_login_app/components/custom_form.dart';
import 'package:flutter_login_app/components/logo.dart';
import 'package:flutter_login_app/pages/home_page.dart';
import 'package:flutter_login_app/pages/login_page.dart';
import 'package:flutter_login_app/size.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        textButtonTheme: TextButtonThemeData(
            style: TextButton.styleFrom(
          backgroundColor: Colors.black,
          foregroundColor: Colors.white,
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
          minimumSize: Size(400, 60),
        )),
      ),

      //앱에서 사용할 화면(경로)를 미리 사용할 수 있다.
      routes: {
        '/login': (context) => LoginPage(),
        '/home': (context) => HomePage(),
      },
      initialRoute: '/login',
    );
  }
}

// class LoginPage extends StatelessWidget {
//   const LoginPage({super.key});
//
//   @override
//   Widget build(BuildContext context) {
//     return ListView(
//       children: [
//         Logo('Login'),
//         SizedBox(height: largeGap),
//         CustomForm(),
//       ],
//     );
//   }
// }

 

페이지들 구성

 

//로그인 페이지 

import 'package:flutter/material.dart';
import 'package:flutter_login_app/components/custom_form.dart';
import 'package:flutter_login_app/components/logo.dart';
import 'package:flutter_login_app/size.dart';

class LoginPage extends StatelessWidget {
  const LoginPage({super.key});

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: ListView(
            children: [
              SizedBox(
                height: xlargeGap,
              ),
              Logo('Login'),
              SizedBox(
                height: largeGap,
              ),
              CustomForm(),
            ],
          ),
        ),
      ),
    );
  }
}

 

 

//홈 페이지 

 

import 'package:flutter/material.dart';
import 'package:flutter_login_app/components/logo.dart';
import 'package:flutter_login_app/size.dart';
import 'package:flutter_svg/flutter_svg.dart';

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              const SizedBox(height: xlargeGap),
              Logo('home Page'),
              const SizedBox(height: largeGap),
              TextButton(
                  onPressed: () {
                    //화면 스택 제거

                    Navigator.pop(context);
                  },
                  child: Text('Get Start'))
            ],
          ),
        ),
      ),
    );
  }
}

 

Navigator를 통해 화면 pop(제거), push(보여지기 ) 설정함 

 

폼의 구성 및 유효성 검사

 

 

import 'package:flutter/material.dart';
import 'package:flutter_login_app/components/custom_text_form_field.dart';
import 'package:flutter_login_app/size.dart';

class CustomForm extends StatelessWidget {
  String _email = '';
  String _password = '';
  CustomForm({super.key});

  // 1. 글로벌 키 선언 - 폼 상태를 관리하기 위한 key 이다.
  final _fromKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _fromKey,
      child: Column(
        children: [
          CustomTextFormField('E-mail', (value) {
            _email = value ?? ''; // null 병합 연산자
          }),
          const SizedBox(height: largeGap),
          CustomTextFormField('Password', (value) {
            _password = value ?? '';
          }),
          const SizedBox(height: largeGap),
          TextButton(
              onPressed: () {
                if (_fromKey.currentState!.validate()) {
                  //유효성 검사가 통과한다면, 아래 로직 호출
                  //save() 메서드를 호출해야되고
                  // 통신요청
                  //로깅 확인
                  print('validation 통과! eamil : $_email ');
                  print('validation 통과! password : $_password ');
                  Navigator.pushNamed(context, '/home');
                }
              },
              child: Text('Login'))
        ],
      ),
    );
  }
}

 

 

커스텀  입력 필드

import 'package:flutter/material.dart';

class CustomTextFormField extends StatelessWidget {
  final String label;
  final FormFieldSetter<String>? onSaved;

  const CustomTextFormField(this.label, this.onSaved, {super.key});

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      obscureText: label == 'Password',
      keyboardType: label == 'E-mail' ? TextInputType.emailAddress : null,
      decoration: InputDecoration(
        labelText: label,
        border: OutlineInputBorder(),
      ),
      validator: (value) {
        if (value == null || value.isEmpty) {
          return '$label 을 입력하세요.';
        }
        return null;
      },
      onSaved: onSaved,
    );
  }
}

 

 

로고 컴포넌트

https://pub.dev/packages/flutter_svg

 

flutter_svg | Flutter package

An SVG rendering and widget library for Flutter, which allows painting and displaying Scalable Vector Graphics 1.1 files.

pub.dev

의존성 주입한 후, 

$ flutter pub add flutter_svg
dependencies:
  flutter_svg: ^2.0.17
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

class Logo extends StatelessWidget {
  final String title;

  const Logo(this.title, {super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SvgPicture.asset(
          'assets/logo.svg',
          height: 70,
          width: 70,
          semanticsLabel: 'Login Logo',
        ),
        Text(
          title,
          style: TextStyle(
            fontSize: 40,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }
}

 

3. 주요 기능 설명

  1. 유효성 검사
    • 입력 값이 비어 있을 경우 에러 메시지를 출력합니다.
    • 이메일 필드와 비밀번호 필드 각각에 적합한 검사를 수행합니다.
  2. 폼 상태 관리
    • _formKey를 사용하여 폼의 상태를 관리합니다.
    • onSaved를 활용해 입력 데이터를 저장합니다.
  3. 로고 표시
    • 로고와 제목을 함께 표시하여 사용자 경험을 높입니다.

4. 결과 화면

로그인 화면은 아래와 같이 구성됩니다:

  • 로고와 제목
  • 이메일 및 비밀번호 입력 필드
  • 로그인 버튼
728x90
반응형

댓글