고도고도
초록 로봇 🤖
고도고도
전체 방문자
6,070
오늘
0
어제
7
  • 분류 전체보기 (137)
    • 🔨 프로젝트 (0)
      • TP 1 (0)
      • WhiteHCCTV (0)
      • FootPrint (0)
    • 💻 개발 (33)
      • TIL (13)
      • Android (4)
      • Kotlin (4)
      • Flutter (5)
      • Node.js (5)
      • Error (2)
    • ✏️ 알고리즘 (6)
      • Graph (6)
      • String (0)
      • Sort (0)
    • ✍️ 코테 준비 (42)
      • Math (1)
      • Implementation (2)
      • String (3)
      • Brute Force (5)
      • Back Tracking (7)
      • Greedy (0)
      • Dynamic Programming (13)
      • Binary Search (0)
      • DFS, BFS (5)
      • Shortest Path (2)
      • Two Pointer (4)
      • MST (0)
    • 📚 CS (6)
      • Operating System (6)
    • ⛹️ 라이프 (50)
      • 2020 겨울방학 모칵코(팀) (13)
      • 2020 겨울방학 모각코(개인) (13)
      • 2021 여름방학 모칵코(팀) (8)
      • 2021 여름방학 모각코(개인) (7)
      • 코딩 테스트 (1)
      • 회고 (7)

블로그 메뉴

  • 홈
  • 깃허브

인기 글

  • 5. SingleChildScrollView, Lis⋯
    2021.08.18
  • [TIL] 22.03.13
    2022.03.13
    [TIL] 22.03.13
  • [문자열 / Kotlin] 2020 KAKAO⋯
    2022.03.11
    [문자열 / Kotlin] 2020 KAKAO⋯
  • [TIL] 22.03.20
    2022.03.20
    [TIL] 22.03.20
  • [투포인터 / Kotlin] BOJ 3273⋯
    2021.12.25
    [투포인터 / Kotlin] BOJ 3273⋯

최근 글

  • [Android] MVVM 패턴 적용기 - 2
    2022.05.14
    [Android] MVVM 패턴 적용기 - 2
  • [코틀린 완전정복] 공변성, 반⋯
    2022.05.02
    [코틀린 완전정복] 공변성, 반⋯
  • [코틀린 완전정복] 제네릭
    2022.04.25
    [코틀린 완전정복] 제네릭
  • [코틀린 완전정복] 여러 종류의⋯
    2022.04.23
    [코틀린 완전정복] 여러 종류의⋯
  • [코틀린 완전정복] 추상 클래스⋯
    2022.04.22
    [코틀린 완전정복] 추상 클래스⋯

최근 댓글

  • 잘보고 갑니다~
    개갓세
  • 좋은 글이네요
    날인로세
  • 잘 보고 갑니다^^
    프로퍼티
hELLO · Designed By 정상우.
고도고도

초록 로봇 🤖

⛹️ 라이프/2021 여름방학 모각코(개인)

[코독하구만 2] 4주차 - Flutter : Shop App 1

2021. 7. 28. 17:04

Udemy 강의가 어느덧 50퍼를 넘겼다. 중간에 어려운 부분도 몇 개 있었지만 이제 어느정도 혼자서 구축할 수 있을 것 같다. 사실 그때 그때 바로 정리하고 싶었는데 어쩌다보니 밀려서 오늘부터라도 바로바로 정리하는 시간을 가지려고 한다.

 

Shop 어플은 우선 GridView 로 상품을 보여주고 상품별로 title 과 좋아요 , 장바구니담기 가 존재한다.

 

우선 이렇게 분리했다. models 에는 상품 에 대해 정의되어 있다.

 

아래가 product.dart 이다. 변수를 선언해주고 생성자까지 구현해주었다.

class Product {
  final String id;
  final String title;
  final String description;
  final int price;
  final String imageUrl;

  Product({
    required this.id,
    required this.title,
    required this.description,
    required this.price,
    required this.imageUrl,
  });
}

 

다음은 상품들을 UI 에 보여주기 위한 screen 이다.

초기에 더미 데이터를 생성시켜줬다.

import 'package:flutter/material.dart';
import '../widgets/product_item.dart';
import '../models/product.dart';

class ProductOverViewScreen extends StatelessWidget {
  final List<Product> loadedProducts = [
    Product(
      id: 'p1',
      title: 'Red Shirt',
      description: 'A red shirt - it is pretty red!',
      price: 29,
      imageUrl:
          'https://cdn.pixabay.com/photo/2016/10/02/22/17/red-t-shirt-1710578_1280.jpg',
    ),
    Product(
      id: 'p2',
      title: 'Trousers',
      description: 'A nice pair of trousers.',
      price: 59,
      imageUrl:
          'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Trousers%2C_dress_%28AM_1960.022-8%29.jpg/512px-Trousers%2C_dress_%28AM_1960.022-8%29.jpg',
    ),
    Product(
      id: 'p3',
      title: 'Yellow Scarf',
      description: 'Warm and cozy - exactly what you need for the winter.',
      price: 19,
      imageUrl:
          'https://live.staticflickr.com/4043/4438260868_cc79b3369d_z.jpg',
    ),
    Product(
      id: 'p4',
      title: 'A Pan',
      description: 'Prepare any meal you want.',
      price: 49,
      imageUrl:
          'https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Cast-Iron-Pan.jpg/1024px-Cast-Iron-Pan.jpg',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("My Shop"),
      ),
      body: GridView.builder(
        padding: const EdgeInsets.all(10),
        itemCount: loadedProducts.length,
        itemBuilder: (ctx, index) => ProductItem(
          loadedProducts[index].id,
          loadedProducts[index].title,
          loadedProducts[index].imageUrl,
        ),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          childAspectRatio: 1.5,
          crossAxisSpacing: 10,
          mainAxisSpacing: 10,
        ),
      ),
    );
  }
}

이후 Widget 부분을 보면 body 에 GridView 를 builder 로 정의해줬다. 다양한 방법이 있지만 builder 가 가장 편하다. builder 를 사용하기 위해선 itemCount itemBuilder gridDelegate 가 필요하다. itemCount 는 GridView 로 그려낼 총 개수를 의미하고, itemBuilder 는 그려낼 아이템을 의미한다. gridDelegate 는 GridView 의 옵션 이다.

 

builder 에서 ProductItem 메소드를 호출하는 것을 볼 수 있는데 품목 에 해당하는 위젯 을 분리하기 위함이다. 그럼 product_item 을 살펴보자.

import 'package:flutter/material.dart';

class ProductItem extends StatelessWidget {
  final String id;
  final String title;
  final String imageUrl;

  ProductItem(this.id, this.title, this.imageUrl);

  @override
  Widget build(BuildContext context) {
    return GridTile(
      child: Image.network(imageUrl, fit: BoxFit.cover),
      footer: GridTileBar(
        backgroundColor: Colors.black54,
        leading: IconButton(
          icon: Icon(Icons.favorite),
          onPressed: () {},
        ),
        title: Text(
          title,
          textAlign: TextAlign.center,
        ),
        trailing: IconButton(
          icon: Icon(
            Icons.shopping_cart,
          ),
          onPressed: () {},
        ),
      ),
    );
  }
}

넣어준 매개변수 id , title , imageUrl 을 이용하여 품목 을 그려낸다. 여기서 GridTile 로 구현하는데 LIstTile 과 동일하다. footer 와 header 가 존재한다. 말 그대로 footer 를 쓰면 바닥에 header 를 쓰면 천장에 구현된다. 예시를 보자. 첫 번째 사진이 header , 두 번째 사진이 footer 이다.

 

 

이후 child 요소들로 leading title trailing 이 존재하고 이들을 이용하여 배치를 할 수 있다. leading 은 front , title 은 ㅇㅇ... trailing 은 back 이라고 생각하면 쉽다. 그렇다면 현재 어플에서는 3가지 를 모두 사용했는데 이 중에 하나라도 사라진다면? 역시 예시를 보자.

 

첫 번째 사진은 leading 을 제거한 사진, 두 번째 사진은 title 을 제거한 사진, 세 번째 사진은 trailing 을 제거한 사진이다.

이렇게 구현이 된다.

 

GridTileBar 를 보니 subTitle 이라는 값이 존재한다. 살펴보자.

 

이후에 GridTile 로 구현한 상품 하단의 좋아요 와 장바구니 버튼을 실제로 동작하도록 구현해봤다. 기존의 방식과 다른 방식으로 구현했는데 Provider 라는 새로운 개념을 도입했다. 사실 이해하는데 좀 어려웠다. 아직도 제대로 이해하지 못하고 있다고 봐도 무방하다. 일단 공식문서를 들고 왔다. 하지만 어려운게 현실...

 

https://pub.dev/packages/provider

 

provider | Flutter Package

A wrapper around InheritedWidget to make them easier to use and more reusable.

pub.dev

 

정리되어 있는 글이 있어서 첨부했다.

https://eunjin3786.tistory.com/255

 

[Flutter] Provider로 앱 상태 관리하기

아래 움짤처럼 여러 화면에서 상태를 공유해야할때 어떻게 해야하는지 State management 문서를 살펴보겠습니다. 1) 선언적으로 생각하기 우선 선언적으로 생각하라고 합니다. SwiftUI 처럼 state가 바

eunjin3786.tistory.com

 

간단하게 설명하자면 Flutter 는 Widget 으로 구성되어 있는데 이게 어플을 제작하다보면 Widget 간의 Depth 가 기하급수적으로 증가하게 된다. main → class A, class B, class c... 뭐 상관 없을수도 있지만 만약에 서로 다른 부모를 갖는 (class A-1과 class C-3 이런 느낌?) 경우에 매번 build 를 다시해야한다. 이렇게 말하면 이해가 어려우니 예시를 들어보자.

 

상품에 좋아요 와 장바구니 버튼이 존재하는데 좋아요 페이지와 장바구니 페이지가 있다고 가정해보자. 버튼이 클릭될 때마다 계속 build 가 발생한다. Widget 의 Depth 가 깊지 않으면 상관이 없지만 연속적으로 inherit 된다고 가정하면 메모리 누수 가 발생할 것이다. 이를 효율적으로 관리하는 것이 바로 provider 이다. 데이터 에 쉽게 접근하겠다는 것이 목표

 

products.dart 와 이를 사용하는 products_grid 를 살펴보자.

import 'package:flutter/material.dart';
import 'product.dart';

class Products with ChangeNotifier {
  List<Product> _items = [
    Product(
      id: 'p1',
      title: 'Red Shirt',
      description: 'A red shirt - it is pretty red!',
      price: 29,
      imageUrl:
          'https://cdn.pixabay.com/photo/2016/10/02/22/17/red-t-shirt-1710578_1280.jpg',
    ),
    Product(
      id: 'p2',
      title: 'Trousers',
      description: 'A nice pair of trousers.',
      price: 59,
      imageUrl:
          'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Trousers%2C_dress_%28AM_1960.022-8%29.jpg/512px-Trousers%2C_dress_%28AM_1960.022-8%29.jpg',
    ),
    Product(
      id: 'p3',
      title: 'Yellow Scarf',
      description: 'Warm and cozy - exactly what you need for the winter.',
      price: 19,
      imageUrl:
          'https://live.staticflickr.com/4043/4438260868_cc79b3369d_z.jpg',
    ),
    Product(
      id: 'p4',
      title: 'A Pan',
      description: 'Prepare any meal you want.',
      price: 49,
      imageUrl:
          'https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Cast-Iron-Pan.jpg/1024px-Cast-Iron-Pan.jpg',
    ),
  ];

  var showFavoritesOnly = false;

  List<Product> get items {
    if (showFavoritesOnly) {
      return _items.where((productItem) => productItem.isFavorite).toList();
    }
    return [..._items];
  }

  Product findById(String id){
    return _items.firstWhere((element) => element.id == id);
  }

  void addProduct() {
    notifyListeners();
  }
}
import 'package:flutter/material.dart';
import '/providers/products.dart';
import '/widgets/product_item.dart';
import 'package:provider/provider.dart';

class ProductsGrid extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final productsData = Provider.of<Products>(context);
    final products = productsData.items;

    return GridView.builder(
      padding: const EdgeInsets.all(10),
      itemCount: products.length,
      itemBuilder: (ctx, index) => ChangeNotifierProvider(
        create: (c) => products[index],
        child: ProductItem(),
      ),
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        childAspectRatio: 1.5,
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
      ),
    );
  }
}

products_grid 를 먼저 살펴보면 Provider.of<자료형>(context) 로 선언한 것을 볼 수 있다. 이것이 바로 Provider 로 관리할 변수이다. ChangeNotifierProvider 는 Provider 로 관리하는 아이템에 상태 변화가 일어나면 setState 해주는 부분이다.

 

import 'package:flutter/material.dart';
import '/providers/product.dart';
import 'package:provider/provider.dart';
import '../screens/product_detail_screen.dart';

class ProductItem extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final product = Provider.of<Product>(context, listen : false);
    return ClipRRect(
      borderRadius: BorderRadius.circular(10),
      child: GridTile(
        child: GestureDetector(
          onTap: () {
            Navigator.of(context).pushNamed(
              ProductDetailScreen.routeName,
              arguments: product.id,
            );
          },
          child: Image.network(product.imageUrl, fit: BoxFit.cover),
        ),
        footer: GridTileBar(
          backgroundColor: Colors.black54,
          leading: Consumer<Product>(
            builder: (ctx, product, child) => IconButton(
              icon: Icon(
                product.isFavorite ? Icons.favorite: Icons.favorite_border,
              ),
              onPressed: () {
                product.toggleFavoriteStatus();
              },
              color: Theme.of(context).accentColor,
            ),
          ),
          title: Text(
            product.title,
            textAlign: TextAlign.center,
          ),
          trailing: IconButton(
            icon: Icon(
              Icons.shopping_cart,
            ),
            onPressed: () {},
            color: Theme.of(context).accentColor,
          ),
        ),
      ),
    );
  }
}

ProductItem 을 살펴보면 역시 Provider.of<Product>(context, listen : false) 로 관리하고 있는 것을 볼 수 있다. 이후에 Consumer 도 등장하는데 Consumer 부분만 새로 build 하게된다.

 

설명이 많이 부족하긴 한데 나도 아직 100% 이해하고 있지는 않은 것 같다. 실제로 사용해보면서 감을 잡아야겠다.

 

소스코드는 아래 링크를 통해 접속하면 확인할 수 있다.

https://github.com/k906506/2021-Summer-Flutter-Study/tree/master/myfourthflutterapp

 

GitHub - k906506/2021-Summer-Flutter-Study: Studying hybrid app development using Dart and Flutter in summer vacation Mogakko

Studying hybrid app development using Dart and Flutter in summer vacation Mogakko 👾 - GitHub - k906506/2021-Summer-Flutter-Study: Studying hybrid app development using Dart and Flutter in summer va...

github.com

 

저작자표시비영리변경금지

'⛹️ 라이프 > 2021 여름방학 모각코(개인)' 카테고리의 다른 글

[코독하구만 2] 6주차 - Flutter : Shop App 3  (0) 2021.08.10
[코독하구만 2] 5주차 - Flutter : Shop App 2  (0) 2021.08.10
[코독하구만 2] 4주차 - Flutter : Shop App 1  (0) 2021.07.28
[코독하구만 2] 3주차 - Flutter : Personal Expense App  (0) 2021.07.22
[코독하구만 2] 2주차 - Flutter : Personal Expense App  (0) 2021.07.15
[코독하구만 2] 1주차 - Flutter : Quiz App  (0) 2021.07.07
    '⛹️ 라이프/2021 여름방학 모각코(개인)' 카테고리의 다른 글
    • [코독하구만 2] 6주차 - Flutter : Shop App 3
    • [코독하구만 2] 5주차 - Flutter : Shop App 2
    • [코독하구만 2] 3주차 - Flutter : Personal Expense App
    • [코독하구만 2] 2주차 - Flutter : Personal Expense App
    고도고도
    고도고도
    안드로이드 개발자가 되고 싶은 컴공생
    댓글쓰기
    다음 글
    [코독하구만 2] 5주차 - Flutter : Shop App 2
    이전 글
    [코독하구만 2] 3주차 - Flutter : Personal Expense App
    • 이전
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 다음