1. Google Fonts 라이브러리 설치

2. Method Refactoring
- 재사용하고 싶은 위젯들을 해당 클래스 내에서 사용할 수 있도록 Refactoring
- 위젯 우클릭 → Refactor → Extract Method 클릭 후 변경할 메서드명 입력
- 앞에 _(언더바) 입력 시 private 설정

3. Class Refactoring (Component)
- 재사용하고 싶은 위젯들을 모아서 하나의 클래스로 Refactoring 후 사용 가능
- 위젯 우클릭 → Refactor → Extract Flutter Widget 클릭 후 클래스명 입력
- 이와 같이 Refactor를 적용한 클래스를 컴포넌트(Component)라고 함

4. 파일 분리
- Convention : 소문자 + 언더바

5. 코드 작성
- main.dart
- 기본 구조 : HomePage 내부에서 화면 작성
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
// 기본 구조 : 추후 작성하고 옮길 것
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Placeholder(),
);
}
}
- homepage.dart
- 페이지를 구분하는 파일을 따로 만드는 것이 좋음
- main에서는 각종 이벤트 및 기초 설정을 담당하는 코드들이 많음
- 스타일을 지정하는 코드가 있으면 가독성을 해침
Widgets
- ListView : 스크롤 바가 있는 Column 또는 Row
- 기본 방향은 Column이나, Row로 바꿀 수 있음
- AppBar : 각종 메뉴 또는 아이콘들을 표시할 수 있는 화면 상단에 표시되는 Navigation Bar
- 내부의 Icon들은 직접 넣어야 함
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_prac_recipe/component/list_item.dart';
import 'package:flutter_prac_recipe/component/menu.dart';
import 'package:flutter_prac_recipe/component/my_title.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ListView(
children: [
_appBar(),
SizedBox(height: 25),
MyTitle("Recipes"),
SizedBox(height: 25),
Menu(),
SizedBox(height: 25),
ListItem("coffee"),
SizedBox(height: 25),
ListItem("burger"),
SizedBox(height: 25),
ListItem("pizza"),
],
),
),
);
}
AppBar _appBar() {
return AppBar(
actions: [
Icon(Icons.search),
SizedBox(width: 16),
Icon(
CupertinoIcons.heart,
color: Colors.redAccent,
),
SizedBox(width: 16),
],
);
}
}
- menu.dart
- 재사용이 가능한 위젯들을 모아서 하나의 클래스로 만든 컴포넌트 (Component)
- 자바와 동일하게 컴포넌트 내부에 컴포넌트를 포함할 수 있음
- 사용 시 해당 클래스를 import 해야 함
Widgets
- Container : 특정 방향(Column, Row)으로 정렬된 내부 item들을 담는 상자
- 위젯들을 하나로 묶기 위해 사용 : 클래스로 선언하여 재사용 가능
- 매직 키 (Alt + Enter) → wrap with widget 선택 후 이름 변경으로 쉽게 생성 가능
import 'package:flutter/material.dart';
import 'package:flutter_prac_recipe/component/menu_item.dart';
class Menu extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Row(
children: [
MenuItem(Icons.food_bank, "ALL"),
SizedBox(width: 25),
MenuItem(Icons.emoji_food_beverage, "Coffee"),
SizedBox(width: 25),
MenuItem(Icons.fastfood, "Burger"),
SizedBox(width: 25),
MenuItem(Icons.local_pizza, "Pizza"),
],
),
);
}
}
- menu_item.dart
- 메뉴 안에 들어갈 아이템을 모아서 하나의 클래스로 재사용할 수 있는 컴포넌트
- Container는 직접 크기 지정 가능
- 클래스 내부에 상태를 만들어서 생성자로 주입 가능, 주입된 상태를 내부에서 활용
Widgets
- Icon : 아이콘을 출력하는 위젯
- Container
- decoration : 컨테이너의 서식 지정 : BoxDecoration 내부에서 지정
- border : 외곽선 지정
- borderRadius : 둥근 모서리 지정
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class MenuItem extends StatelessWidget {
IconData mIcon;
String mText;
MenuItem(this.mIcon, this.mText);
@override
Widget build(BuildContext context) {
return Container(
width: 60,
height: 80,
decoration: BoxDecoration(
border: Border.all(color: Colors.black12),
borderRadius: BorderRadius.circular(30),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
mIcon,
size: 30,
color: Colors.redAccent,
),
Text(
mText,
style: GoogleFonts.patuaOne(),
),
],
),
);
}
}
- my_title.dart
- 제목과 같은 범용성이 높은 위젯은 따로 만들어두는 것이 재사용 및 관리에 용이
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class MyTitle extends StatelessWidget {
String title;
MyTitle(this.title);
@override
Widget build(BuildContext context) {
return Text(
title,
style: GoogleFonts.patuaOne(fontSize: 30),
);
}
}
- list_item.dart
- 이미지, 제목, 내용을 하나로 묶어서 하나의 컴포넌트로 관리
- 이미지는 assets 폴더 내부의 이미지 경로를 받아서 사용
- 이미지의 배율을 조절하여 사진이 잘리지 않도록 배치
Widgets
- AspectRatio : 내부 Item의 비율 조절
- aspectRatio : double 값을 받아서 사용하나, n / m의 형식으로 사용할 수 있음 (n : m)
- ClipRRect : 내부 Item을 모서리가 둥근 사각형에 담음
- Image.asset : URL을 통해 이미지를 불러옴
- fit : 이미지 맞춤 설정
- BoxFit.cover : 늘리기
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class ListItem extends StatelessWidget {
String title;
ListItem(this.title);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 16 / 9,
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset(
"$title.jpeg",
fit: BoxFit.cover,
),
),
),
Text(
title,
style: GoogleFonts.patuaOne(fontSize: 25),
),
Text(
"Have you ever made your own $title? Once you've tried a homemade $title, you'll never go back.",
style: GoogleFonts.patuaOne(),
),
],
);
}
}
6. Result
- 화면 스크롤 가능


Share article