URL에서 가져온 데이터를 화면에 보여주자!
그런데... 그러기 위해서는 메뉴 카드를 만들어야 한다. 그럼 메뉴 카드들을 만들어보자!
메뉴 카드들은 어느 폴더에 넣는 게 좋을까?
처음에 난 당연히 restaurant 폴더에 넣어야 될 거라고 생각했다.
하지만! 스웨거 API를 보면 맨 앞에 URL 값들로 인해 이미 나눠져 있음!
user와 관련된 건 user 태그로 나눠져 있고,
auth와 관련된 건 auth 태그로 나눠져 있음...
메뉴(상품)을 보면...
product 태그로 나눠져 있는 걸 알 수 있다.
그래서 폴더를 따로 만들거임!
① lib/product/component 폴더 생성
그 안에 product_card.dart 파일을 만들어준다.
② Container를 Row 위젯으로 수정
Container를 Row 위젯으로 수정
좌에서 우로 이미지, 글자들에 랜더링 되고 있으니까 Row 위젯으로 수정하고 코드 작성.
이미지는 샘플로 일단 넣어두자.
import 'package:flutter/material.dart';
class ProductCard extends StatelessWidget {
const ProductCard({super.key});
Widget build(BuildContext context) {
return Row(
children: [
Image.asset('asset/img/food/ddeok_bok_gi.jpg'),
],
);
}
}
그리고 이 product card를 보여주기 위해서 restaurant_detail_screen.dart 코드에 ProductCard를 넣어준다.
ㅋㅋㅋ 그런데 지금 이미지가 엄청 크게 들어가서 오버플로우 발생!
오버플로우를 해결하기 위해서는 ProductCard로 가서 너비, 높이를 정해줘야 한다.
fit: BoxFit.cover를 주면 최대한의 사이즈를 차지시킬 수 있음.
좌우가 좀 잘렸지만 정사각형이 된 것을 볼 수 있다.
그리고 이미지 모서리도 둥글게 깎아줘야 한다.
ClipRRect로 감싸주고 borderRadius 주기.
③ 메뉴 설명 넣기
메뉴 사진 옆에 글자는 어떻게 넣을까?
현재 ClipRRect가 왼쪽 끝에 붙어있는 상태이다. 그럼 그 옆에 남는 공간에 글자를 넣어줘야 하는데,
그러기 위해서는 Expanded로 감싸주면 된다.
💣 트러블이슈
제목, 내용, 가격 Text 컴포넌는 모두 위아래로 같은 간격으로 나뉘어져야 함.
그래서 mainAxisAlignment: MainAxisAlignment.spaceBetween 을 줬으나 바뀌지 않음...
칼럼에 색깔을 줘서 확인해보자.
빨간색 공간만큼만 차지 중이라서 여기서 spaceBetween을 해봤자,
현재 배치된 게 맞다고 생각하고 바뀌지 않게 된다.
왜 이럴까?
이유는 Row 컴포넌트 안에 넣은 값(Children)들은 각각 고유의 높이를 갖게 됨!
이건 위젯의 본능이라고 할 수 있다..
그래서 이미지를 보여주는 부분이 더 높은 크기를 차지하고 있더라도
나머지 부분은 각 위젯에 알맞는 사이즈를 차지하게 되는 것.
내가 원하는 건 일단 빨간색 공간이 이미지 위아래 선과 같아야 하고,
각각 내용 사이 간격도 일정해야 되는 것이기 때문에
이 문제를 해결하기 위해 Row를 IntrinsicHeight로 감싸준다.![]()
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_actual/common/const/colors.dart';
class ProductCard extends StatelessWidget {
const ProductCard({super.key});
Widget build(BuildContext context) {
return IntrinsicHeight(
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.asset(
'asset/img/food/ddeok_bok_gi.jpg',
width: 110,
height: 110,
fit: BoxFit.cover,
),
),
const SizedBox(width: 16),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// 제목
Text(
'떡볶이',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
// 내용
Text(
'전통 떡볶이의 정석! \n아주 맛있어요! 처음 드시는 분들에게 강추합니다~',
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14,
color: BODY_TEXT_COLOR,
),
),
// 가격
Text(
'₩10000',
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 12,
color: PRIMARY_COLOR,
fontWeight: FontWeight.w500),
),
],
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_actual/common/layout/default_layout.dart';
import 'package:flutter_actual/product/component/product_card.dart';
import 'package:flutter_actual/restaurant/component/restaurant_card.dart';
class RestaurantDetailScreen extends StatelessWidget {
const RestaurantDetailScreen({super.key});
Widget build(BuildContext context) {
return DefaultLayout(
title: '불타는 떡볶이',
child: Column(
children: [
RestaurantCard(
image: Image.asset('asset/img/food/ddeok_bok_gi.jpg'),
name: '불타는 떡볶이',
tags: const ['떡볶이', '매움', '치즈'],
ratingsCount: 100,
deliveryTime: 30,
deliveryFee: 3000,
ratings: 4.76,
isDetail: true,
detail: '맛있는 떡볶이',
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: ProductCard(),
),
],
),
);
}
}
현재까지 최종적인 결과 화면