
1. RecipeTitle 커스텀 위젯 만들기
- 모든 위젯에는 제약 조건이 있음
- 컬럼의 부모가 바디 → 바디는 기계마다 다름
- 바디의 크기는 앱바 바로 밑에서 끝까지 = html의 바디와 동일
- 바디 안에 컬럼이 있음
- 컬럼의 제약 조건

- 화면의 크기가 바껴도 재사용 가능함
끝까지 늘어나는데 감싸는 컨테이너를 만들면 크기를 조절할 수 있음
double.infinity // 부모의 크기까지 늘어남

2. 현재 뷰 확인하기
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../components/recipe_body.dart';
class RecipePage extends StatelessWidget {
const RecipePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appbar(),
body: RecipeBody(),
);
}
AppBar _appbar() {
return AppBar(
actions: [
Icon(CupertinoIcons.search), // 시그니처로 키 값 없음
SizedBox(width: 15),
Icon(
CupertinoIcons.heart,
color: Colors.redAccent,
),
SizedBox(width: 15),
],
);
}
}

3. Align으로 정렬하기
- ListView는 따로 정렬 키워드를 제공해주지 않음
import 'package:flutter/cupertino.dart';
import 'package:recipe_app2/components/recipe_menu.dart';
import 'package:recipe_app2/components/recipe_title.dart';
class RecipeBody extends StatelessWidget {
const RecipeBody({
super.key,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
child: ListView(
children: [
Align(
alignment: Alignment.center,
child: RecipeTitle()),
RecipeMenu(),
],
),
);
}
}

- Align 사용하기 전 상황
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 20),
child: Row( //1. 메뉴 아이템들의 방향이 수평 방향이기 때문
mainAxisAlignment: MainAxisAlignment.end,
children: [
_buildMenuItem(Icons.food_bank, "ALL"), // 2. 재사용
SizedBox(width: 25),
_buildMenuItem(Icons.emoji_food_beverage, "Coffee"), // 3. 재사용
SizedBox(width: 25),
_buildMenuItem(Icons.fastfood, "Burger"), // 4. 재사용
SizedBox(width: 25),
_buildMenuItem(Icons.local_pizza, "Pizza"), // 5. 재사용
],
),
);
}

4. 이미지와 텍스트 넣기
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:recipe_app2/components/recipe_menu.dart';
import 'package:recipe_app2/components/recipe_title.dart';
class RecipeBody extends StatelessWidget {
const RecipeBody({
super.key,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView(
children: [
RecipeTitle(),
RecipeMenu(),
SizedBox(
width: double.infinity,
child: Column(
children: [
Image.asset("assets/images/coffee.jpeg", fit: BoxFit.cover),
Text("Coffee", style: TextStyle(fontSize: 20)),
Text(
"Have you ever made your own Coffee? Once you've tried a homemade Coffee, you'll never go back.",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
)
],
),
);
}
}

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:recipe_app2/components/recipe_menu.dart';
import 'package:recipe_app2/components/recipe_title.dart';
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView(
children: [
RecipeTitle(),
RecipeMenu(),
RecipeListItem(),
],
),
);
}
}
class RecipeListItem extends StatelessWidget {
const RecipeListItem({
super.key,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(20),
child:
Image.asset("assets/images/coffee.jpeg", fit: BoxFit.cover)),
Text("Coffee", style: TextStyle(fontSize: 20)),
Text(
"Have you ever made your own Coffee? Once you've tried a homemade Coffee, you'll never go back.",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
);
}
}
- 사진 모서리 라운딩하기

- aspectRatio로 비율을 이용한 크기 조절하기!!
import 'package:flutter/material.dart';
import 'package:recipe_app2/components/recipe_menu.dart';
import 'package:recipe_app2/components/recipe_title.dart';
class RecipeBody extends StatelessWidget {
const RecipeBody({
super.key,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView(
children: [RecipeTitle(), RecipeMenu(), RecipeListItem()],
),
);
}
SizedBox RecipeListItem() {
return SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 1 / 2, // 비율로 조절하기
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset("assets/images/coffee.jpeg",
fit: BoxFit.cover)),
),
Text("Coffee", style: TextStyle(fontSize: 20)),
Text(
"Have you ever made your own Coffee? Once you've tried a homemade Coffee, you'll never go back.",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
);
}
}
- 나머지 이미지도 넣어주기
- 사진이름과 사진 타이틀을 변수로 사용하기
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:recipe_app2/components/recipe_menu.dart';
import 'package:recipe_app2/components/recipe_title.dart';
class RecipeBody extends StatelessWidget {
const RecipeBody({
super.key,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView(
children: [
RecipeTitle(),
RecipeMenu(),
RecipeListItem(imgName: "coffee.jpeg", title: "Coffee"),
RecipeListItem(imgName: "pizza.jpeg", title: "Pizza"),
RecipeListItem(imgName: "burger.jpeg", title: "Burger"),
],
),
);
}
}
class RecipeListItem extends StatelessWidget {
final imgName;
final title;
const RecipeListItem({required this.imgName, required this.title});
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 2 / 1,
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset("assets/images/${imgName}", fit: BoxFit.cover),
),
),
Text("Coffee", style: TextStyle(fontSize: 20)),
Text(
"Have you ever made your own ${title}? Once you've tried a homemade ${title}, you'll never go back.",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
);
}
}



- for문 돌리기
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:recipe_app2/components/recipe_menu.dart';
import 'package:recipe_app2/components/recipe_title.dart';
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView(
children: [
RecipeTitle(),
RecipeMenu(),
RecipeListItem(title: "coffee",),
RecipeListItem(title: "pizza",),
RecipeListItem(title: "burger",),
],
),
);
}
class RecipeListItem extends StatelessWidget {
final title; // 편하게 해보려고 한개만 받음
const RecipeListItem({required this.title})
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(20),
child:
Image.asset("assets/images/${title}.jpeg", fit: BoxFit.cover)),
Text("Coffee", style: TextStyle(fontSize: 20)),
Text(
"Have you ever made your own ${title}? Once you've tried a homemade ${title}, you'll never go back.",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
);
}
}
list.map((e) =>RecipeListItem(title: e)).toList() // 하나만 할 때는 가능
import 'package:flutter/material.dart';
import 'package:recipe_app2/components/recipe_menu.dart';
import 'package:recipe_app2/components/recipe_title.dart';
class RecipeBody extends StatelessWidget {
RecipeBody({
super.key,
});
final list = ["coffee", "pizza", "burger"]; // List<String> 타입
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView(
children: [
RecipeTitle(),
RecipeMenu(),
// list.map((e) =>RecipeListItem(title: e)).toList() // 하나만 할 때는 가능
for(String text in list) RecipeListItem(title: text),
],
),
);
}
}
class RecipeListItem extends StatelessWidget {
final title;
const RecipeListItem({required this.title});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 25),
child: SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 2 / 1,
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child:
Image.asset("assets/images/${title}.jpeg", fit: BoxFit.cover),
),
),
Text("${title}", style: TextStyle(fontSize: 20)),
Text(
"Have you ever made your own ${title}? Once you've tried a homemade ${title}, you'll never go back.",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
),
);
}
}
Share article