1. Project 생성
- 이전 방법 참조
2. 경로 설정
- main.dart
- 로그인 버튼을 눌렀을 때 다른 화면으로 이동하도록 주소 설정
- routes : 어떤 경로를 받았을 때 동작할 함수(행위) 결정
import 'package:flutter/material.dart';
import 'package:loginapp/page/home_page.dart';
import 'package:loginapp/page/login_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp();
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: "/login",
routes: {"/home": (context) => HomePage(), "/login": (context) => LoginPage()},
);
}
}
3. 코드 작성
- login_page.dart
- 로그인 화면
- 이메일, 비밀번호를 입력하고 로그인 버튼을 누르면 메인 화면으로 넘어가도록 설정
- ListView : 앱의 내부 키보드로 인해 화면이 줄어듬 → Column으로 지정할 경우 화면이 깨짐
import 'package:flutter/material.dart';
import 'package:loginapp/component/m_form.dart';
import 'package:loginapp/component/m_logo.dart';
import '../size.dart';
class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ListView(
children: [
SizedBox(height: xxlGap),
MLogo("Login"),
SizedBox(height: lGap),
MForm(),
],
),
),
);
}
}
- home_page.dart
- 로그인 한 이후 메인 화면
- Navigator.pop(context) : 이전 화면으로 돌아가기
import 'package:flutter/material.dart';
import 'package:loginapp/component/m_button.dart';
import 'package:loginapp/component/m_logo.dart';
import '../size.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ListView(
children: [
SizedBox(height: xxlGap),
MLogo("Care Soft"),
SizedBox(height: lGap),
MButton("Get Started", () {
Navigator.pop(context);
}),
],
),
),
);
}
}
- m_logo.dart
- SVG 파일을 사용하여 크기가 커져도 이미지가 깨지지 않음 : 벡터 파일
Widgets
- SvgPictures.asset : asset에서 SVG 파일을 받아서 출력하는 위젯
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class MLogo extends StatelessWidget {
String title;
MLogo(this.title);
@override
Widget build(BuildContext context) {
return Column(
children: [
SvgPicture.asset("logo.svg", width: 70, height: 70),
Text(
title,
style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
),
],
);
}
}
- m_form.dart
- 데이터를 서버에 전송하기 위한 form
- 데이터를 전송하기 위해 필요한 컴포넌트들은 form에 묶어서 사용
- CrossAxisAlignment.stretch : 자식들의 보조 축 길이(너비)를 화면 끝까지 늘려줌
- minWidth : double.infinity
- TextEditingController : text에 대한 처리가 가능한 Controller
- .text : 입력 받은 데이터 값을 Text로 반환
Widgets
- Form : 데이터를 전달하기 위해 사용하는 위젯
import 'package:flutter/material.dart';
import 'package:loginapp/component/m_button.dart';
import 'package:loginapp/component/m_text_box.dart';
import '../size.dart';
class MForm extends StatelessWidget {
TextEditingController _email = TextEditingController();
TextEditingController _password = TextEditingController();
void submit(BuildContext context) {
var requestBody = {"email": _email.text, "password": _password.text};
print("전송할 데이터 : $requestBody");
Navigator.pushNamed(context, "/home");
}
@override
Widget build(BuildContext context) {
return Form(
child: Column(
// min 값을 double.infinity로 늘려줌
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
MTextBox("Email", _email),
SizedBox(height: sGap),
MTextBox("Password", _password, isPassword: true),
SizedBox(height: mGap),
MButton("Login", () => submit(context)),
],
),
);
}
}
- m_text_box.dart
- 텍스트를 입력 받아 TextEditingController에 전달하는 컴포넌트
- bool isPassword를 통해 비밀번호를 입력받을 경우 입력칸을 *로 표시하게 설정 가능
import 'package:flutter/material.dart';
import 'package:loginapp/component/m_text_field.dart';
class MTextBox extends StatelessWidget {
String division;
bool isPassword;
TextEditingController controller;
MTextBox(this.division, this.controller, {this.isPassword = false});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(division),
MTextField("Enter $division", controller, isPassword: isPassword),
],
);
}
}
- m_text_field.dart
- TextEditingController를 통해 입력값을 전달
- 스타일 설정 가능
- Enabled(Default), Focused, Error, FocusedError 등 4가지 경우에 대해 설정 가능
Widgets
- TextFormField : 텍스트를 입력할 수 있는 위젯
- controller : TextEditingController를 연결
- decoration : 해당 위젯의 스타일 지정
- obscureText : 텍스트를 ‘*’로 표시할 지에 대한 여부
- hintText : 텍스트가 입력되지 않았을 때 표시할 String = placeholder
- hintStyle : hintText의 스타일 지정
import 'package:flutter/material.dart';
class MTextField extends StatelessWidget {
String placeholder;
bool isPassword;
TextEditingController controller;
MTextField(this.placeholder, this.controller, {this.isPassword = false});
@override
Widget build(BuildContext context) {
return TextFormField(
controller: controller,
obscureText: isPassword,
decoration: InputDecoration(
// 1. enabledBorder : 기본 디자인
// 2. focusedBorder : 포커스가 잡혔을 때 기본 디자인
// 3. errorBorder : 기본 에러 디자인
// 4. focusedErrorBorder : 포커스가 잡혔을 때 기본 에러 디자인
border: OutlineInputBorder(borderRadius: BorderRadius.circular(15)),
errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15)),
focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15)),
hintText: placeholder,
hintStyle: TextStyle(color: Colors.black26),
),
);
}
}
- m_button.dart
- 입력값을 서버 측에 전달하고, 화면을 전환하는 버튼을 생성하는 컴포넌트
- 입력값은 submit이라는 함수로 콘솔에 출력하는 행위를 통해 전달
import 'package:flutter/material.dart';
class MButton extends StatelessWidget {
String title;
var submit;
MButton(this.title, this.submit);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: submit,
style: ElevatedButton.styleFrom(backgroundColor: Colors.black, fixedSize: Size(double.infinity, 60)),
child: Text(
title,
style: TextStyle(color: Colors.white),
),
);
}
}
- size.dart
- 각 화면에서 사용할 수 있는 gap의 크기를 미리 지정하여 사용
- 디자인의 통일성 부여
double sGap = 5;
double mGap = 10;
double lGap = 20;
double xxlGap = 100;
4. Result
- 로그인 화면

- 이메일, 비밀번호 입력 후 Login 버튼을 누르면 메인 화면으로 이동 및 콘솔에 정보 출력

- 메인 화면

- 콘솔

Share article