
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
