iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0
Mobile Development

Flutter Didilong系列 第 21

D-21 Provider 購物車實作 (中) | Flutter筆記

  • 分享至 

  • xImage
  •  

承接上篇文章 D-20 Provider 購物車實作(上) | Flutter筆記
介紹購物車設計

購物車CartModel實體,存在於多個畫面
否則目錄頁加一件商品,卻不會在購物車裡面

Cart.dart

import 'dart:collection';
import 'package:flutter/widgets.dart';
import 'package:flutter_account_note/shop/model/catalog.dart';

class CartModel extends ChangeNotifier {
  final List<int> _itemIds = []; //加購的商品id存放
  late CatalogModel _catalog; //私有目錄 僅能透過以下get,set 讀取和寫入

  //1. 取得目錄內容
  CatalogModel get catalog => _catalog;

  //2. 設定目錄內容
  set catalog(CatalogModel newCatalog) {
    _catalog = newCatalog;
    notifyListeners();
  }
  //---------------------

  //_itemIds是選購的商品
  //map將id快速轉換成List<item>
  //白話: 購物車商品列表
  List<Item> get items => _itemIds.map((id) => _catalog.getById(id)).toList();

  //總價格計算 fold會將list內容加總 , 0代表初始值
  int get totalPrice => items.fold(0, (total, current) => total + current.price);


  //------------------
  // add removeAll
  // 要對購物車操作 新增商品 移除全部
  // 所以皆需要notifyListeners 告訴我們畫面要更新了

  void add(Item item) {
    _itemIds.add(item.id);
    notifyListeners();
  }

  void removeAll() {
    _itemIds.clear();
    notifyListeners();
  }

  void remove(Item item) {
    _itemIds.remove(item.id);
    notifyListeners();
  }
}

catalogView.dart

import 'package:flutter/material.dart';
import 'package:flutter_account_note/shop/model/cart.dart';
import 'package:flutter_account_note/shop/model/catalog.dart';
import 'package:provider/provider.dart';

class Catalog extends StatelessWidget {
  const Catalog({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          _appBar(),
          const SliverToBoxAdapter(
            child: SizedBox(height: 12),
          ),
          //產生商品列表 單一個商品由_listItem產生
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => _listItem(index),
              childCount: 4,
            ),
          ),
        ],
      ),
    );
  }
}

class _appBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SliverAppBar(
      title: Text(
        'Catalog',
        style: Theme.of(context).textTheme.displayMedium,
      ),
      actions: [
        IconButton(
          onPressed: () => Navigator.pushNamed(context, '/cart'),
          icon: const Icon(Icons.shopping_cart),
        )
      ],
    );
  }
}

class _listItem extends StatelessWidget {
  final int index;

  const _listItem(this.index);
  @override
  Widget build(BuildContext context) {
    //讀取CatalogModel中的商品目錄index 代表得到目錄中第幾個
    var item = context.select<CatalogModel, Item>(
      (catalog) => catalog.getByPosition(index),
    );

    var textTheme = Theme.of(context).textTheme.titleLarge;
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: LimitedBox(
        maxHeight: 48,
        child: Row(
          children: [
            AspectRatio(
              aspectRatio: 1,
              child: Container(
                color: item.color,
              ),
            ),
            const SizedBox(width: 24),
            Expanded(
              child: Text(item.name, style: textTheme),
            ),
            const SizedBox(width: 24),
            _addButton(item: item),
          ],
        ),
      ),
    );
  }
}

//商品按鈕 點擊後加入購物車
class _addButton extends StatelessWidget {
  const _addButton({Key? key, required this.item}) : super(key: key);
  final Item item;
  @override
  Widget build(BuildContext context) {
  
    //檢查商品(Item)是否在購物車(Cart)中
    var isInCart = context.select<CartModel, bool>((cart) => cart.items.contains(item));

    return TextButton(
      onPressed: isInCart
          ? null
          : () {
              //點擊後 , 條件判斷沒有在購物車的話 ,即加入購物車
              var cart = context.read<CartModel>();
              cart.add(item);
            },
      child: isInCart ? const Icon(Icons.check, semanticLabel: 'ADDED') : const Text('ADD'),
      style: ButtonStyle(
        overlayColor: MaterialStateProperty.resolveWith<Color?>((states) {
          if (states.contains(MaterialState.pressed)) {
            return Theme.of(context).primaryColor;
          }
          return null;
        }),
      ),
    );
  }
}


上一篇
D-20 Provider 購物車實作(上) | Flutter筆記
下一篇
D-22 Provider 購物車實作 (下) | Flutter筆記
系列文
Flutter Didilong30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言