만들면서 배우는 플러터 앱 프로그래밍을 바탕으로 연습했습니다.
코드를 짜기 전, 최상단 폴더에 assets 폴더를 만들고 이미지와 폰트를 넣어줍니다.
이미지 폴더 전체 사용 설정 (pubspec.yaml)
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/
images/ 해당 경로 하위의 모든 파일을 가져올 수 있게 됩니다.
폰트 사용 설정 (pubspec.yaml)
# example:
fonts:
- family: PatuaOne
fonts:
- asset: assets/fonts/PatuaOne-Regular.ttf
해당 폰트를 불러올 때 입력할 폰트의 이름을 지정해줍니다.
코드
- main.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'recipe_list_item.dart';
import 'recipe_menu.dart';
import 'recipe_title.dart';
// 플러터 코드의 시작점
void main() {
// MyApp 위젯을 루트 위젯으로 만들어 주는 함수
// 사전 기반 지식 ---. 위젯 트리를 떠올려 주세요
runApp(const MyApp());
}
// 위젯을 만들 때 크게 두 가지로 구분한다
// statelessWidget 위젯은 상태 변경이 없는 위켓을 화면에 그릴 때 선택
// 상속 문법 사용
// 우리들만의 약속 - MyApp -> 머터리얼 앱이라는 객체를 활용하자
class MyApp extends StatelessWidget {
// 생성자 - 선택적 명명 매개변수 (값을 넣어도 되고 안 넣어도 되고)
const MyApp({super.key});
// 보통 루트 위젯을 시작할 때 머터리얼 앱을 많이 활용한다
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(fontFamily: 'PatuaOne'),
// 앱이 실행되었을 때 첫 페이지를 지정할 수 있다
home: RecipePage(),
);
}
} // end of class
// 우리들만의 규칙 2 - 페이지라고 이름 붙이는 클래스는 스캐아 폴더를 활용하자
class RecipePage extends StatelessWidget {
const RecipePage({super.key});
@override
Widget build(BuildContext context) {
// 시각적 레이아웃 구조를 잡아주는 위젯
// app 영역
// body 영역
// bottom 영역
return Scaffold(
backgroundColor: Colors.white,
appBar: _buildRecipeAppBar(),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView(
children: [
RecipeTitle(),
RecipeMenu(),
RecipeListItem('coffee', 'Made Coffee'),
RecipeListItem('burger', 'Made Burger'),
RecipeListItem('pizza', 'Made Pizza'),
],
),
),
),
);
}
// 메서드를 만들어 보자
// private
AppBar _buildRecipeAppBar() {
return AppBar(
backgroundColor: Colors.white,
bottom: PreferredSize(
preferredSize: Size.fromHeight(3.0),
child: Container(
color: Colors.black,
height: 1.0,
)),
shape: Border(
bottom: BorderSide(color: Colors.black12, width: 1),
),
iconTheme: IconThemeData(color: Colors.black),
// elevation: 1.0,
actions: [
Icon(CupertinoIcons.search, color: Colors.black),
SizedBox(width: 15),
Icon(CupertinoIcons.heart, color: Colors.red),
SizedBox(width: 15)
],
);
}
}
- recipe_title.dart
import 'package:flutter/material.dart';
// 레시피 타이틀 클래스를 만들어 보자 (위젯 기준)
class RecipeTitle extends StatelessWidget {
const RecipeTitle({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 20),
child: Text('Recipes', style: TextStyle(fontSize: 30)),
);
}
}
- recipe_menu.dart
import 'package:flutter/material.dart';
class RecipeMenu extends StatelessWidget {
const RecipeMenu({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
_buildMenuIcon(Icons.food_bank, 'ALL'),
SizedBox(width: 25),
_buildMenuIcon(Icons.emoji_food_beverage, 'Coffee'),
SizedBox(width: 25),
_buildMenuIcon(Icons.fastfood, 'Burger'),
SizedBox(width: 25),
_buildMenuIcon(Icons.local_pizza, 'Pizza'),
],
),
);
}
// 메서드 만들어 보기
Widget _buildMenuIcon(IconData mIcon, String text) {
// 컨테이너 위젯에 컬러 속성과 데코레이션 함께 쓰면 무조건 오류
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, color: Colors.red),
SizedBox(height: 5),
Text(text, style: TextStyle(color: Colors.black54))
],
),
);
}
}
- recipe_list_item.dart
import 'package:flutter/material.dart';
class RecipeListItem extends StatelessWidget {
final String imageName;
final String title;
// 하드코딩
const RecipeListItem(this.imageName, this.title, {super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 이미지 비율 지정할 수 있다
AspectRatio(
aspectRatio: 2 / 1,
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset(
'assets/images/${imageName}.jpeg',
fit: BoxFit.cover,
)),
),
SizedBox(height: 10),
// 텍스트1
Text(title, style: TextStyle(fontSize: 20)),
// 텍스트2
Text(
'Have you ever..To add assets to your application, add an assets section, '
'like this To add assets to your application, add an assets section, like this',
style: TextStyle(color: Colors.black38, fontSize: 12)),
],
),
);
}
}
아래의 문헌을 참고하여 작성된 포스팅입니다.
최주호, 김근호, 이지원(공저) 『만들면서 배우는 플러터 앱 프로그래밍』, 앤써북, 2023.
'Flutter' 카테고리의 다른 글
[Flutter] 연습하기3 - Flutter profile app (0) | 2025.01.10 |
---|---|
[Flutter] 플러터의 스크롤 위젯을 알아보자 (0) | 2025.01.08 |
[Flutter] 플러터의 Basic Widget 살펴보기 (0) | 2025.01.08 |
[Flutter] Everything is a Widget - 플러터 기본기 다지기 (0) | 2025.01.08 |
[Flutter] 연습하기1 - flutter store app (0) | 2025.01.07 |