본문 바로가기
개발일지/GoodWishes

[굿위시 제작기] 12. 굿즈 검색 페이지 제작하기

by 박기린 2024. 11. 3.

 


굿즈와 위시를 검색할 수 있는 페이지

굿즈와 위시가 많이 쌓이면, 특정 물건을 찾기 위해선 검색 기능이 필수입니다.

이 기능을 지원하는 '검색 페이지'를 제작하는 것이 이번 목표입니다.

 

 

 


검색 페이지의 코드 전문

import 'package:flutter/material.dart';
import 'package:goodwishes/Models/goods_model.dart';
import 'package:goodwishes/Models/wish_model.dart';
import 'package:goodwishes/constants/ui_numbers.dart';
import 'package:goodwishes/widgets/change_goods_wish_button.dart';
import 'package:goodwishes/widgets/goods/searching_list.dart';

import 'package:goodwishes/widgets/section_title.dart';
import 'package:goodwishes/widgets/top_with_profile.dart';
import 'package:goodwishes/widgets/wish/wish_searching_list.dart';
import 'package:provider/provider.dart';

class SearchPage extends StatefulWidget {
  const SearchPage({
    super.key,
  });

  @override
  State<SearchPage> createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  bool isGoods = true;
  List<Goods> searchingList = [];
  List<Wish> searchingListWish = [];

  @override
  Widget build(BuildContext context) {
    void isGoodsChangeHandler() {
      setState(() {
        isGoods = !isGoods;
      });
    }

    final goodsListProvider = Provider.of<GoodsListProvider>(context);
    final wishListProvider = Provider.of<WishListProvider>(context);

    return SingleChildScrollView(
      scrollDirection: Axis.vertical,
      child: Padding(
        padding: const EdgeInsets.symmetric(
            horizontal: UIDefault.pageHorizontalPadding),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const TopWithProfile(title: 'Search'),
            const SizedBox(
              height: UIDefault.sizedBoxHeight,
            ),
            ChangeGoodsWishButton(
                isGoods: isGoods, onClick: isGoodsChangeHandler),
            const SizedBox(
              height: UIDefault.sizedBoxHeight,
            ),
            SizedBox(
              width: MediaQuery.of(context).size.width,
              height: 100,
              child: TextFormField(
                onChanged: (value) {
                  setState(() {
                    isGoods
                        ? searchingList = goodsListProvider.searchGoods(value)
                        : searchingListWish =
                            wishListProvider.searchWish(value);
                  });
                },
                keyboardType: TextInputType.multiline,
                maxLines: 1,
                style: const TextStyle(
                  fontSize: 17,
                ),
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: '검색어를 입력하세요',
                ),
              ),
            ),
            isGoods
                ? const SectionTitle(
                    titleText: '검색된 굿즈',
                  )
                : const SectionTitle(
                    titleText: '검색된 위시',
                  ),
            isGoods
                ? SearchingList(
                    serachingList: searchingList,
                  )
                : WishSearchingList(
                    serachingList: searchingListWish,
                  ),
          ],
        ),
      ),
    );
  }
}

 

 

 

 


검색 페이지의 상단 구성 - 굿즈 위시 변경 버튼

검색페이지의 상단 구성은

[굿즈 위시 변경 버튼][검색창]입니다.

 

 

 

 

[굿즈 위시 변경 버튼]은 '굿즈와 위시 변경 버튼 글 (https://arnopark.tistory.com/932)'의 위젯을 그대로 가져와서 사용했습니다.

 

 

 

 

굿즈 추가 페이지와 동일하게 isGoods state를 사용합니다.

버튼을 누르면, '굿즈'와 '위시' 모드로 각각 전환할 수 있습니다.

 

 

 

 


검색 페이지의 상단 구성 - 검색창

다음은 검색 페이지의 핵심 기능인 '검색창'입니다.

 

 

 

 

 

검색어를 입력하면, 굿즈 모드일 경우 GoodListProvider의 검색 메소드, 위시 모드일 경우 WishListProvider의 검색 메소드를 사용해서, 상황에 맞는 검색 결과물을 보여줍니다.

 

 

 

 

 

(좌) 굿즈 모드 (우) 위시 모드

실제 작동화면에서 검색어를 입력하면, 각 모드에 맞춰서 검색 결과를 1행에 2열로 출력합니다.

 

 

 

 

 


검색결과 출력 위젯 - SearchingList

import 'package:flutter/material.dart';
import 'package:goodwishes/Models/goods_model.dart';
import 'package:goodwishes/widgets/goods/searching_list_el.dart';

class SearchingList extends StatelessWidget {
  final List<Goods> serachingList;

  const SearchingList({
    super.key,
    required this.serachingList,
  });

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      padding: const EdgeInsets.only(bottom: 100, top: 20),
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: MediaQuery.of(context).size.width ~/ 180,
        childAspectRatio: 0.8, // 위젯 출력 비율
        crossAxisSpacing: 10, // 가로 여백
      ),
      physics: const NeverScrollableScrollPhysics(),
      shrinkWrap: true,
      itemCount: serachingList.length,
      itemBuilder: (context, index) {
        return SearchingListEl(
          item: serachingList[index],
        );
      },
    );
  }
}

 

 

 

빨간 네모 부분의 출력을 담당하는 위젯입니다.

 

 

 

 

 

GridView.builder()를 사용해서, 자동으로 휴대폰 크기에 맞춰서, 2열로 굿즈가 출력되게 했습니다.

 

 

 

 

 

 


검색된 굿즈 한 칸 출력 - SearchingListEl

import 'package:flutter/material.dart';
import 'package:goodwishes/Models/goods_model.dart';
import 'package:goodwishes/pages/goods_detail_page.dart';

class SearchingListEl extends StatelessWidget {
  final Goods item;

  const SearchingListEl({
    super.key,
    required this.item,
  });

  @override
  Widget build(BuildContext context) {
    return TextButton(
      style:
          const ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.zero)),
      onPressed: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => GoodsDetailPage(id: item.id),
          ),
        );
      },
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            height: 160,
            width: 160,
            decoration: BoxDecoration(
              color: Colors.grey,
              borderRadius: BorderRadius.circular(15),
              image: DecorationImage(
                fit: BoxFit.cover,
                image: MemoryImage(item.thumbnail),
              ),
            ),
          ),
          Text(
            item.goodsName,
            style: const TextStyle(
              fontSize: 15,
            ),
          ),
        ],
      ),
    );
  }
}

 

 

사진의 빨간 네모처럼, SearchingList의 한 칸을 담당하는 위젯입니다.

 

 

 

 

이 한 칸을 누르면, 해당 굿즈의 상세페이지로 이동하는 기능도 넣었습니다.

 

 

끝.

 

반응형