앱개발/Flutter 실습
실습 #2 - 레시피 앱 만들기
subindev
2025. 1. 13. 09:09
- github
flutter/flutter_recipe_app at main · subin3578/flutter
Contribute to subin3578/flutter development by creating an account on GitHub.
github.com
오늘은 레시피 앱을 만들어보는 실습을 통해 Appbar, Container, Icon, ClipRRect, AspectRatio, ListView 위젯과 폰트 변경에 대하여 알아보는 시간을 가지겠습니다.


폰트 설정
# example:
fonts:
- family: PatuaOne
fonts:
- asset: assets/fonts/PatuaOne-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
만들어보기
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_recipe_app/recipe_list_item.dart';
import 'package:flutter_recipe_app/recipe_menu.dart';
import 'package:flutter_recipe_app/recipe_title.dart';
// 플러터 코드의 시작점
void main() {
// MyApp 위젯을 루트 위젯으로 만들어 주는 함수 이다.
// 사전 기반 지식 ---. 위젯 트리를 떠올려 주세요
runApp(MyApp());
}
// 위젯을 만들 때 크게 두가지로 구분한다.
// StatelessWidget 위젯은 상태 변경이 없는 위젯을 화면에 그릴 때 선택한다.
// 상속문법 사용
// 우리들만에 약속 - MyApp -> 머터리얼 앱 객체를 활용하자.
class MyApp extends StatelessWidget {
// 생성자 - 선택적 명명 매개 변수( 값을 넣어도 안 넣어도 되고)
MyApp({super.key});
// 보통 루트 위젯을 시작할 때 MaterialApp을 많이 활용 한다.
@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(
appBar: _buildRecipeAppBar(),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView(
children: [
RecipeTitle(),
RecipeMenu(),
// 레시피 아이템
RecipeListItem('coffee', 'Made Coffee'),
RecipeListItem('burger', 'Made Burger'),
RecipeListItem('pizza', 'Made Pizza'),
// 레시피 아이템
// 레시피 아이템
],
),
),
);
} // end of build method
// 메서드를 만들어 보자.
// private
AppBar _buildRecipeAppBar() {
return AppBar(
backgroundColor: Colors.white,
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)
],
);
}
}
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(
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'),
],
),
);
}
// 메서드 만들어 보기
// Container 위젯을 꾸며 주고 싶다면 ...
Widget _buildMenuIcon(IconData mIcon, String text) {
// Container 위젯에 color 속성과 decoration 함께 쓰면
// 무조건 오류
return Container(
width: 60,
height: 80,
decoration: BoxDecoration(
border: Border.all(color: Colors.black12),
borderRadius: BorderRadius.circular(25),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(mIcon, color: Colors.red),
SizedBox(height: 5),
Text(
text,
style: TextStyle(color: Colors.black54),
)
],
),
);
}
}