
1. 텍스트 위젯 추가
일단 해당 탭을 정의하는 Text 를 넣었다.
처음에는 Grid 이미지와 별개로 존재한다 생각하여 컬럼 내부에 넣었더니, 스크롤이 올라가도
"00님\nBookBox 에서 추천하는 책을 만나보세요.",
라는 텍스트가 계속 존재했음.
따라서 ListView 내부에 넣었다.Text(
"00님\nBookBox 에서 추천하는 책을 만나보세요.",
style: theme.bodyLarge,
),
2. GridView 설정
ListView 는 스크롤이 영원히 늘어나는 속성을 갖고 있기 때문에
GridView
를 사용하기 적절하지 않다.
그러나 사용하고 싶기 때문에 그리드뷰 빌더에 두가지 속성을 추가 했다.physics: NeverScrollableScrollPhysics(), // 그리드 스크롤 비활성화
shrinkWrap: true, // 그리드의 높이를 내용에 맞게 조절
기본적으로
ListView
, GridView
둘 다 스크롤을 중복해서 갖게 되기 때문에, 그리드 뷰의 스크롤을 비활성화 하고, shrinkWrap
를 사용하여 높이를 임의로 할당했다.2-1. 그리드 이미지 크기 구하기
그리드뷰의 넓이는 미디어 쿼리를 사용하여 계산했다.
var size = MediaQuery.of(context).size;
final double itemHeight = (size.height - kToolbarHeight - 24) / 2;
final double itemWidth = size.width / 2.3;
GridView.builder(
physics: NeverScrollableScrollPhysics(), // 그리드 스크롤 비활성화
shrinkWrap: true, // 그리드의 높이를 내용에 맞게 조절
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 10,
crossAxisCount: 3,
mainAxisSpacing: 10,
childAspectRatio: (itemWidth / itemHeight),
),
childAspectRatio 를 사용하여 컨테이너의 크기를 지정했다.
그리고 리턴값에
RecommendItem
위젯을 호출한다.3. 위젯 만들기

위젯은 적절하게 스타일을 주고, 글자수가 길이를 초과하는 것을 방지하기 위해
maxLines
, overflow
를 사용했다.
maxLines
: 줄 길이 설정overflow
: 넓이 초과하는 글자 처리 법maxLines: 2,
overflow: TextOverflow.ellipsis,
전체 코드
import 'package:bookbox/core/constants/size.dart';
import 'package:bookbox/core/constants/styles.dart';
import 'package:bookbox/ui/main/home/recommend_tab/recommend_item.dart';
import 'package:flutter/material.dart';
class RecommendTab extends StatelessWidget {
@override
Widget build(BuildContext context) {
TextTheme theme = textTheme();
var size = MediaQuery.of(context).size;
final double itemHeight = (size.height - kToolbarHeight - 24) / 2;
final double itemWidth = size.width / 2.3;
return Padding(
padding: const EdgeInsets.all(gap_s),
child: ListView(
children: [
Padding(
padding: const EdgeInsets.only(bottom: gap_s), // 아래 간격 조정
child: Text(
"00님\nBookBox 에서 추천하는 책을 만나보세요.",
style: theme.bodyLarge,
),
),
GridView.builder(
physics: NeverScrollableScrollPhysics(), // 그리드 스크롤 비활성화
shrinkWrap: true, // 그리드의 높이를 내용에 맞게 조절
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 10,
crossAxisCount: 3,
mainAxisSpacing: 10,
childAspectRatio: (itemWidth / itemHeight),
),
itemCount: 12,
itemBuilder: (context, index) {
return RecommendItem(
imageUrl:
"https://picsum.photos/id/${index + 10}/200/280", // 이미지 URL
title: "책 제목\n제목길면청길면 $index", // 책 제목
author: "저자이름 $index 엄청길면", // 저자 이름
);
},
),
],
),
);
}
}
import 'package:bookbox/core/constants/size.dart';
import 'package:flutter/material.dart';
class RecommendItem extends StatelessWidget {
final String imageUrl; // 이미지 URL
final String title; // 책 제목
final String author; // 저자
RecommendItem({
required this.imageUrl,
required this.title,
required this.author,
});
@override
Widget build(BuildContext context) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 이미지 표시
ClipRRect(
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
width: 2,
),
),
child: Image.network(
imageUrl, // 너비를 부모에 맞추기
fit: BoxFit.cover, // 이미지가 잘리도록 설정
),
),
),
Padding(
padding: const EdgeInsets.all(8.0), // 패딩 추가
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
maxLines: 2,
overflow: TextOverflow.ellipsis, // 제목 스타일
),
Text(
author,
style: TextStyle(color: Colors.grey),
maxLines: 1,
overflow: TextOverflow.ellipsis, // 저자 스타일
),
],
),
),
],
),
);
}
}
Share article