1. 기본 세팅

assets 폴더를 만든 후 svg 파일을 넣는다.


pubspect.yaml 설정 후 pub get 을 누른다.
2. 테마 만들기
theme.dart
import 'package:flutter/material.dart';
final ThemeData appTheme = ThemeData(
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
backgroundColor: Colors.black,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
minimumSize: Size(400, 60),
),
),
);
main.dart
import 'package:flutter/material.dart';
import 'theme.dart'; // 사용자 정의 테마를 import합니다.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: appTheme, // 테마 지정
);
}
}
3. Svg 파일 불러오기
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'theme.dart'; // 사용자 정의 테마를 import합니다.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: appTheme, // 테마 지정
// initialRoute: "/login",
home: Scaffold(
body: ListView(
children: [
SizedBox(height: 100),
Column(
children: [
SvgPicture.asset(
"assets/logo.svg",
height: 70,
width: 70,
),
Text(
"Login",
style: TextStyle(fontSize: 40,fontWeight: FontWeight.bold),
),
],
),
],
),
),
);
}
}

4. Route 사용하기
Route 는 화면을 이동할 때 사용한다.
initialRoute
: 앱이 시작할 때 최초로 시작될 화면을 지정한다.
routes
: 이동할 화면을 설정한다. 익명함수를 통해 설정한다.
pages/login_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class LoginPage extends StatelessWidget {
const LoginPage({
super.key,
});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
SizedBox(height: 100),
Column(
children: [
SvgPicture.asset(
"assets/logo.svg",
height: 70,
width: 70,
),
Text(
"Login",
style: TextStyle(fontSize: 40,fontWeight: FontWeight.bold),
),
],
),
],
),
);
}
}
Scaffold 이하의 코드를 LoginPage 로 컴퍼넌트를 분리한다. 해당 페이이지는 “/login” 주소로 설정한다.
main.dart
import 'package:flutter/material.dart';
import 'package:login_app/page/login_page.dart';
import 'theme.dart'; // 사용자 정의 테마를 import합니다.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: appTheme, // 테마 지정
initialRoute: "/login", // 앱이 시작하면 로그인 페이지로 이동
routes: {
"/login": (context) => LoginPage(), // "/login"가 요청되면 LoginPage() 를 호출한다
},
);
}
}

5. 로그인 페이지 디자인하기
5.1. Form 웨젯, TextFormField
Form
위젯과 TextFormField
를 사용해 유효성 검사를 쉽게 할 수 있다.import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class LoginPage extends StatelessWidget {
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
LoginPage({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView( // 키패드가 올라오면 화면을 기리기때문에 ListView 로 만듬
children: [
SizedBox(height: 100),
Column(
children: [
SvgPicture.asset(
"assets/logo.svg",
height: 70,
width: 70,
),
Text(
"Login",
style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
),
Form(
key: formKey,
child: Column(
children: [
Text('Email'),
SizedBox(height: 20),
TextFormField(
validator: (value) =>
value!.isEmpty ? "Please enter some text" : null,
decoration: InputDecoration(
hintText: "Enter email",
enabledBorder: OutlineInputBorder( // 기본 디자인
borderRadius: BorderRadius.circular(20),
),
focusedBorder: OutlineInputBorder( // 손가락 터치시 디자인
borderRadius: BorderRadius.circular(20),
),
errorBorder: OutlineInputBorder( //에러 발생시
borderRadius: BorderRadius.circular(20),
),
focusedErrorBorder: OutlineInputBorder( // 에러 발생 후 손가락 터치했을 때
borderRadius: BorderRadius.circular(20),
),
),
),
],
),
),
],
),
],
),
);
}
}


5.2. 컴포넌트 분리, 변수화하기
pages/login_page.dart
import 'package:flutter/material.dart';
import '../components/custom_form.dart';
import '../components/logo.dart';
class LoginPage extends StatelessWidget {
LoginPage({Key?key}) :super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView( // 키패드가 올라오면 화면을 기리기때문에 ListView 로 만듬
children: [
SizedBox(height: 100),
Logo(logoText: "Login"),
CustomForm(),
],
),
);
}
}
components/logo.dart
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class Logo extends StatelessWidget {
final logoText ;
Logo({required this.logoText});
@override
Widget build(BuildContext context) {
return Column(
children: [
SvgPicture.asset(
"assets/logo.svg",
height: 70,
width: 70,
),
Text(
logoText,
style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
),
],
);
}
}
components/custom_text_form.dart
import 'package:flutter/material.dart';
class CustomTextFormField extends StatelessWidget {
final text;
CustomTextFormField({required this.text});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(text),
TextFormField(
validator: (value) =>
value!.isEmpty ? "Please enter some text" : null,// 입력값이 없다면 출력
obscureText: text == "Password" ? true : false, // 비밀번호를 입력하면 **** 처리하기
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/custom_form.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'custom_text_form_field.dart';
class CustomForm extends StatelessWidget {
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
CustomForm({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Form(
key: formKey,
child: Column(children: [
CustomTextFormField(text: "Email"), // 컴포넌트로 만들어 재사용할 수 있다.
SizedBox(height: 20),
CustomTextFormField(text: "Password"),
],
),
);
}
}
6. 버튼 만들기
custom_form.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'custom_text_form_field.dart';
class CustomForm extends StatelessWidget {
final GlobalKey<FormState> formKey = GlobalKey<FormState>(); // 추가된 부분
CustomForm({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Form(
key: formKey, // 수정된 부분
child: Column(
children: [
CustomTextFormField(text: "Email"),
SizedBox(height: 20),
CustomTextFormField(text: "Password"),
SizedBox(height: 20),
TextButton(
onPressed: () { //버튼을 누르면 "/home"
if (formKey.currentState!.validate() ) {
Navigator.pushNamed(context, "/home");
}
},
child: Text("Login"),
)
],
),
);
}
}

버튼이 생성되었다.

버튼을 누르면 유효성 검사가 된다.
main.dart
import 'package:flutter/material.dart';
import 'package:login_app/page/login_page.dart';
import 'theme.dart'; //
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: appTheme, // 테마 지정
initialRoute: "/login",
routes: {
"/login": (context) => LoginPage(),
"/home" :(context) => HomePage(),
},
);
}
}
버튼을 누르면 “/home” 이 요청된다. 버튼을 누르면 이동될 HomePage 클래스를 만들자.
7. HomePage 만들기
pages/home_page.dart
import 'package:flutter/material.dart';
import '../components/logo.dart';
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
SizedBox(height: 200),
Logo(logoText: "Care Soft"),
],
),
);
}
}

버튼을 누르면 “/home” 으로 이동한다.
Share article