inblog logo
|
나새끼메이커

    책 검색 앱 제작 (2)

    Eungae's avatar
    Eungae
    Jan 12, 2026
    책 검색 앱 제작 (2)
    Contents
    검색 함수 세팅검색 아이콘그리드 뷰그리드 뷰 사용법bottom sheetHomePage 내에 bottm sheet 구현트러블 슈팅Bottom sheet 내부 디자인 — 별도의 위젯으로 관리
    검색 함수 세팅검색 아이콘그리드 뷰그리드 뷰 사용법bottom sheetHomePage 내에 bottm sheet 구현Bottom sheet 내부 디자인 — 별도의 위젯으로 관리
     
     
     
    💡
    대원칙
    • 실습은 최소 3번씩 해보기.
    • 안 되면 더 하기.
    • 안 하고 불안해 하지 않기.
     

    검색 함수 세팅

    위치: class HomePage 아래 → TextEditingController와 같은 위상.
    void onSearch(String text) { }
    → TextField 하위에
    onSubmitted: onSearch, // onSubmitted: 키보드에서 done을 눌렀을 때 작동될 작업 설정 -> onSearch
     
     

    검색 아이콘

    @override Widget build(BuildContext context) { return GestureDetector( onTap: () { FocusScope.of(context).unfocus(); }, child: Scaffold( appBar: AppBar( actions: [ GestureDetector( onTap: () { onSearch(textEditingController.text); }, // 버튼의 터치영역은 44 디바이스 픽셀 이상으로 설정할 것 -> 이하일 경우 오류 발생 child: Container( width: 50, height: 50, // 컨테이너에 배경색이 없으면 자녀위젯에만 터치 이벤트가 적용됨. color: Colors.transparent, child: Icon(Icons.search), ), ), ],
     
     

    그리드 뷰

    그리드 뷰 사용법

    GridView : 격자 형태의 뷰
    • 기본 사용법
      • GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, // 한 행에 들어갈 위젯 갯수 childAspectRatio: 3 / 4, // 각 위젯 비율 crossAxisSpacing: 10, // 위젯간 가로 간격 mainAxisSpacing: 10, // 위젯간 세로 간격 ), children: [ Image.network('https://picsum.photos/300/400'), Image.network('https://picsum.photos/300/400'), ], )
    • builder 생성자 이용
      • itemCount 속성 갯수만큼 itemBuilder 속성에 들어가는 함수 호출
      • itemBuilder에서는 return되는 위젯이 GridView children에 하나씩 들어간다고 생각! ⇒ 동일한 위젯인데 안에 내용만 바뀔 때 주로 사용
      • GridView.builder( itemCount: 20, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, childAspectRatio: 3 / 4, crossAxisSpacing: 10, mainAxisSpacing: 10, ), itemBuilder: (context, index) { return Image.network( 'https://picsum.photos/300/400', fit: BoxFit.cover, ); }, )
    • gridDelegate
      • 그리드 레이아웃을 제어하는 클래스
      • SliverGridDelegateWithFixedCrossAxisCount
        • 한 행에 들어갈 위젯 갯수를 고정하고 싶을때 사용
          • GridView.builder( padding: EdgeInsets.all(20), itemCount: 10, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, childAspectRatio: 3 / 4, crossAxisSpacing: 10, mainAxisSpacing: 10, ), itemBuilder: (context, index) { return Image.network( 'https://picsum.photos/300/400', fit: BoxFit.cover, ); }, )
      • SliverGridDelegateWithMaxCrossAxisExtent
        • 위젯의 가로 크기를 정해서 사용하고 싶을 때
          • GridView.builder( padding: EdgeInsets.all(20), itemCount: 10, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 50, childAspectRatio: 3 / 4, crossAxisSpacing: 10, mainAxisSpacing: 10, ), itemBuilder: (context, index) { return Image.network( 'https://picsum.photos/300/400', fit: BoxFit.cover, ); }, )
     
     
    body: GridView.builder( padding: EdgeInsets.all(20), itemCount: 10, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, childAspectRatio: 3 / 4, crossAxisSpacing: 10, mainAxisSpacing: 10, ), itemBuilder: (context, index) { return Image.network( 'https://fastly.picsum.photos/id/705/300/400.jpg?hmac=fS4rfBAi01bPlJVcEOYfDlIGjxgtg21XNhBAgAThAOQ', ); }, ),
    📍여기서 git push
     

    bottom sheet

    HomePage 내에 bottm sheet 구현

    itemBuilder: (context, index) { return GestureDetector( onTap: () { showModalBottomSheet( context: context, builder: (context) { return Container( width: double.infinity, height: 300, child: Text("data"), ); }, ); }, child: Image.network( 'https://fastly.picsum.photos/id/705/300/400.jpg?hmac=fS4rfBAi01bPlJVcEOYfDlIGjxgtg21XNhBAgAThAOQ', ), );
    💡

    트러블 슈팅

    처음에 Container 없이 Text로 바텀시트 만들었을 때는 바텀시트가 너무 작게 나오는 문제가 있었다. 이를 조정하기 위해 어디에 Container를 입혀야 할까? → 정답은 Text에 입히는 것이었다.
    이 감각을 어떻게 가질 수 있을까.

    point
    • 부모 위젯은 자식의 위젯의 크기를 존중한다.
    • → 무엇이 자식 위젯인가.
    📍여기서 git push
     

    Bottom sheet 내부 디자인 — 별도의 위젯으로 관리

    home/ ├── widgets/ │ └── home_bottom_sheet.dart ← 새로 생성 ├── home_page.dart └── home_view_model.dart
     
    home_bottom_sheet.dart
    import 'package:flutter/material.dart'; class HomeBottomSheet extends StatelessWidget { @override Widget build(BuildContext context) { return Container(width: double.infinity, height: 200, child: Row()); } }
    ⇒ HomePage에 HomeBottomSheet 적용
    itemBuilder: (context, index) { return GestureDetector( onTap: () { showModalBottomSheet( context: context, builder: (context) { return HomeBottomSheet(); }, );
     
    home_bottom_sheet.dart 에서 Row()
    import 'package:book_search/presentation/detail/detail_page.dart'; import 'package:flutter/material.dart'; class HomeBottomSheet extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: double.infinity, height: 300, padding: EdgeInsets.only(top: 20, right: 20, left: 20, bottom: 60), child: Row( children: [ Image.network( 'https://fastly.picsum.photos/id/705/300/400.jpg?hmac=fS4rfBAi01bPlJVcEOYfDlIGjxgtg21XNhBAgAThAOQ', fit: BoxFit.cover, ), SizedBox(width: 20), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "해리포터", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), ), Text( "J.K.롤링", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14), ), Text("해리포터와 마법사의 돌을 찾아가는 여정", style: TextStyle(fontSize: 14)), Spacer(), GestureDetector( // "자세히 보기" 클릭 시 작업되도록 onTap: () { Navigator.push( // DetailPage로 넘어가도록 context, MaterialPageRoute( builder: (context) { return DetailPage(); }, ), ); }, child: Container( // 글씨 부분 주변을 클릭해도 넘어가도록 Container 씌움 width: double.infinity, height: 50, color: Colors.transparent, alignment: Alignment.center, child: Text( "자세히 보기", style: TextStyle( color: Colors.blueAccent, fontWeight: FontWeight.bold, ), ), ), ), ], ), ), ], ), ); } }
    📍 git push
     
     
    Share article
    Contents
    검색 함수 세팅검색 아이콘그리드 뷰그리드 뷰 사용법bottom sheetHomePage 내에 bottm sheet 구현트러블 슈팅Bottom sheet 내부 디자인 — 별도의 위젯으로 관리

    나새끼메이커

    RSS·Powered by Inblog