본문 바로가기
개발/Flutter

[Flutter] 로그인 폼 UI

by 가시죠 2022. 1. 1.
반응형

사용된 컴포넌트

Form : https://api.flutter.dev/flutter/widgets/Form-class.html

TextFormField : https://api.flutter.dev/flutter/material/TextFormField-class.html

Navigator : https://api.flutter.dev/flutter/dart-html/Navigator-class.html

Route : https://api.flutter.dev/flutter/widgets/Route-class.html

flutter_svg : https://pub.dev/packages/flutter_svg

Theme : https://api.flutter.dev/flutter/material/Theme-class.html

 

프로젝트 구조

 

pubspec.yaml

name: flutter_login
description: flutter login ui app
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
  sdk: ">=2.15.1 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2

  #외부 라이브러리 https://pub.dev/packages/flutter_svg
  flutter_svg: ^1.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^1.0.0

flutter:
  uses-material-design: true
  # assets 경로 지정
  assets:
    - assets/

 

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_login/pages/home_page.dart';
import 'package:flutter_login/pages/login_page.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Login App',
      // 테마설정
      theme: ThemeData(
        /// 전체 TextButton 테마를 지정하면 모든 TextButton에 테마가 적용된다.
        textButtonTheme: TextButtonThemeData(
          style: TextButton.styleFrom(
            backgroundColor: Colors.black,
            primary: Colors.white,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(30),
            ),
            minimumSize: Size(400, 60)
          )
        ),
      ),
      /// 화면이동을 위해 route를 사용
      initialRoute: "/login", // 초기 경로 설정
      routes: { // 경로 목록
        "/login" : (context) => LoginPage(),
        "/home" : (context) => HomePage()
      },
    );
  }
}

 

size.dart : 사이즈를 위한 상수 선언 파일

const double small_gap  = 5.0;
const double medium_gap = 10.0;
const double large_gap  = 20.0;
const double xlarge_gap = 100.0;

 

components/custom_form.dart : 폼 입력 화면 구성

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

class CustomForm extends StatelessWidget {
  // global key
  final _formkey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      // global key를 form에 지정하여 해당 key로 form의 상태를 관리
      key: _formkey,
      child: Column(
        children: [
          CustomTextFormField("Email"),
          SizedBox(height: medium_gap,),
          CustomTextFormField("Password"),
          SizedBox(height: large_gap,),
          // 로그인 버튼
          TextButton(
              onPressed: (){
                /// 유효성 검사
                if (_formkey.currentState!.validate()) {
                  /// 네비게이터로 화면 이동, routes의 이름을 적어 이동한다
                  Navigator.pushNamed(context, "/home");
                }
              },
              child: Text("Login"),
          )
        ],
      ),
    );
  }
}

 

components/custom_text_form_field.dart : 텍스트폼필드를 커스텀하게 정의

import 'package:flutter/material.dart';
import 'package:flutter_login/size.dart';

class CustomTextFormField extends StatelessWidget {
  final String text;
  const CustomTextFormField(this.text);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(text),
        SizedBox(height: small_gap,),
        TextFormField(
          // 1. [유효성 체크]
          // 공백일 경우 메시지 출력..
          validator: (value) => value!.isEmpty
              ? "필수항목입니다"
              : null,

          // 2. [마킹처리]
          // text가 Password일 경우 마킹 처리 true
          obscureText: text == "Password" ? true : false,

          // 3. [데코레이션]
          // 힌트 문자나 여러가지 데코레이션 기능 추가
          decoration: InputDecoration(
            hintText: "Enter $text.", // 힌트문자
            enabledBorder: OutlineInputBorder(
              // 기본 모양
              borderRadius: BorderRadius.circular(20),
            ),
            focusedBorder: OutlineInputBorder(
              // 포커스 되었을 경우 모양
              borderRadius: BorderRadius.circular(20),
            ),
            errorBorder: OutlineInputBorder(
              // 에러 발생 시 모양
              borderRadius: BorderRadius.circular(20)
            ),
            focusedErrorBorder: OutlineInputBorder(
              // 에러 발생 후 포커스 되었을 경우 모양
              borderRadius: BorderRadius.circular(20)
            )
          ),
        )
      ],
    );
  }
}

 

components/logo.dart : 로고 사용, flutter_svg 외부 라이브러리 사용

import 'package:flutter/cupertino.dart';
import 'package:flutter_svg/flutter_svg.dart';

/// flutter_svg 외부 라이브러리를 이용해 svg 이미지를 가져온다.
class Logo extends StatelessWidget {
  final String title;
  //const Logo({Key? key}) : super(key: key);
  const Logo(this.title);

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

 

pages/login_page.dart : 로그인 페이지

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

// stless 단축키로 자동 생성..
class LoginPage extends StatelessWidget {

  const LoginPage({Key? key}) : super(key: key);

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

 

pages/home_page.dart : 로그인 이후 화면 페이지

import 'package:flutter/material.dart';
import 'package:flutter_login/components/logo.dart';

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ListView(
          children: [
            SizedBox(height: 200,),
            Logo("환영합니다."),
            SizedBox(height: 50,),
            TextButton(
                onPressed: (){
                  Navigator.pop(context);
                },
                child: Text("로그인 페이지로 이동"))
          ],
        ),
      ),
    );
  }
}

 


참고 : https://github.com/flutter-coder/flutter-ui-book1/tree/master/flutter_login

반응형

댓글