Flutter 2商城App实战指南:全面支持Null safety,助你快速开发

2024-12-08 0 542

// 简单使用
import 'package:dio/dio.dart';
void main() async {
  var dio = Dio();
  final response = await dio.get('https://google.com');
  print(response.data);  
}
// response.data 这里返回的是json字符串,可使用 data['name'] 获取值
// 要想像 Object 一样使用 data.name 获取。需要转换为Dart模型(Json to Dart)

在pub.dev的插件市场中,瀑布流布局的插件种类繁多,让人看得眼花缭乱。面对这么多选项,如何挑选出适合自己项目的插件变得尤为重要。这其中的每一个细节都值得仔细考虑。这情形就好像在众多珍宝中寻找最耀眼、最适合自己的那一颗。

{
  "name": "jsdawn",
  "age": 18,
  "gender": ""
}

// To parse this JSON data, do
//     final person = personFromJson(jsonString);
import 'dart:convert';
// 字符串转为`Person`模型
Person personFromJson(String str) => Person.fromJson(json.decode(str));
// `Person`数据转为字符串
String personToJson(Person data) => json.encode(data.toJson());
class Person {
    Person({
        this.name,
        this.age,
        this.gender,
    });
    String name;
    int age;
    String gender;
  
    // json中字段不可少,否则需要判空:json["name"] ?? ""
    factory Person.fromJson(Map<String, dynamic> json) => Person(
        name: json["name"],
        age: json["age"],
        gender: json["gender"],
    );
    Map<String, dynamic> toJson() => {
        "name": name,
        "age": age,
        "gender": gender,
    };
}

考虑项目开发环境

// 这里 DefaultAssetBundle 的 loadString 加载 Json 文件,模拟接口调用
String jsonString = await DefaultAssetBundle.of(context)
    .loadString('assets/json/data.json');
// 字符串转为 Dart Model
final person = personFromJson(jsonString);
print(person.name); // jsdawn

assets:
  - assets/svg/

项目使用的是v2.x版本的开发环境,这个版本能够兼容Null。因此,选择的瀑布流布局插件也必须能够适配Null。根据以往的项目经验,若插件不兼容开发环境的特性,后续可能会遇到众多兼容性问题。在开发过程中,这就像建造房屋时基础不稳,后续楼层建设将充满挑战。此外,不同版本对插件的要求各异,忽视这些要求可能导致项目架构不稳定。在实际操作中,若插件不支持Null,模块间或数据间的交互可能会出现意料之外的错误。

import 'package:flutter_svg/svg.dart';
Padding(
    padding: const EdgeInsets.symmetric(vertical: 4),
    // SvgPicture.asset 加载svg静态资源
    child: SvgPicture.asset('assets/svg/category_phone.svg', height: 35),
),

项目环境中存在诸多特性,各团队可能关注点各异。不过,对于本项目而言,v2.x版本对Null的支持显得尤为关键。

参考插件的LIKES数量

满足开发需求之外,插件获得点赞数同样关键。众多开发者点赞,表明该插件在功能与稳定性上有所长处。有项目曾随意选用点赞稀少的插件,结果使用时故障频发。选用点赞数较高的插件,能降低这种风险。在插件市场,人们的选择通常映射出插件的真实品质。数据显示,点赞数多的插件用户满意度通常也较高,这些都是开发实践中能直观感受到的。

import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
@override
Widget build(BuildContext context) {
    // 使用插件的 MasonryGridView 类编写瀑布流布局
    return MasonryGridView.count(
      controller: _scrollController,
      padding: widget.list.isNotEmpty
          ? const EdgeInsets.symmetric(vertical: 12)
          : null,
      shrinkWrap: true,
      physics: const NeverScrollableScrollPhysics(),
      crossAxisCount: 2, // 列的数量
      mainAxisSpacing: 20, // 主轴项之间的距离
      crossAxisSpacing: 12, // 交叉轴项之间的距离
      itemCount: widget.list.length,
      // 列表项生成器
      itemBuilder: (context, index) {
        return GoodsListItem(widget.list[index]);
      },
    );
}

当然,这并非衡量事物的唯一准则,然而,它确实是一个至关重要的考量因素。因为,公众的视角在一定程度上,确实具有一定的参考意义。

瀑布流布局需求匹配度

Flutter 2商城App实战指南:全面支持Null safety,助你快速开发

项目需求插件需适配瀑布流布局。以商品列表组件为例,页面布局需呈现良好视觉感受。我曾观察过一个项目,选用的插件看似满足瀑布流布局标准,但处理商品图片时却出现故障。在现实应用中,商品列表的呈现可能左右用户购买意愿。若商品图片拉伸扭曲或间距不均,用户体验将大打折扣。因此,在选择瀑布流布局插件时,务必细致检查其是否完全符合项目布局要求,这一点至关重要。

{
    "id": 46,
    "title": "能方研影",
    "price": 61.96,
    "cover": "http://dummyimage.com/300x300/B9C6C3&text=shopping%20mall",
    "count": 3,
    "color": "蓝色",
    "size": "XS",
}

另外,还需注意不同商品在陈列上各有不同需求,有的商品适合用多张图片来展示,而有的则以文字描述为主,这些因素都需纳入考量范围。

class CartInfoModel {
  CartInfoModel({
    required this.id,
    required this.title,
    required this.price,
    required this.cover,
    required this.count,
    required this.color,
    required this.size,
  });
  int id;
  String title;
  double price;
  String cover;
  int count;
  String color;
  String size;
  ...
}

本地存储相关事项

购物车商品的本地保存对于项目来说至关重要。当用户没有结账就关闭应用,期待下次打开时购物车商品还在,这直接影响到用户的体验。以我们平时用的购物应用为例,若关闭后再打开发现购物车为空,难免会感到沮丧。在实现本地保存时,可以借助特定的插件实现数据的长期保存。在具体的项目中,通过执行pubadd指令来下载这些插件,这是基本步骤。同时,当购物车里的数据发生变化,比如商品数量的增减等,要确保及时更新到本地存储,这样才能确保下次打开应用时购物车数据准确无误。

import 'package:flutter_riverpod/flutter_riverpod.dart';
...
const cartPrefsKey = 'cartList';
class CartNotifier extends ChangeNotifier {
  // 购物车列表
  final List<CartInfoModel> cartList = <CartInfoModel>[];
  // 总数量
  int get totalCount {
    int total = 0;
    for (var item in cartList) {
      total += item.count;
    }
    return total;
  }
  // 总价格
  double get totalPrice {
    double total = 0;
    for (var item in cartList) {
      total += item.price * item.count;
    }
    return total;
  }
  // 加入购物车
  // 更新购物车数量
  // 移除购物车指定项
  // 查询/初始化购物车
}
// ChangeNotifierProvider 用法
final cartProvider = ChangeNotifierProvider<CartNotifier>((ref) {
  return CartNotifier();
});

本地存储可能存在数据安全的隐患,但在此项目里并未涉及。显然,若涉及用户隐私等关键信息,安全因素同样十分关键。

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
    runApp(
        // ProviderScope包裹入口组件,提供全局状态
        ProviderScope(child: MyApp())
    );
}

全局状态管理

// 读取购物车列表
List<CartInfoModel> list =
    ref.watch(cartProvider.select((value) => value.cartList));
// 读取结算价格
double totalPrice =
    ref.watch(cartProvider.select((value) => value.totalPrice));
// 读取总数量
int totalCount =
    ref.watch(cartProvider.select((value) => value.totalCount));
// 调用方法
ref.read(cartProvider.notifier).pushCart(_cartInfo);

购物车全局状态管理非常重要。它需在多个页面间共享,比如在商品详情页展示购物车商品数,并允许直接添加商品;在购物车页面上还能调整商品数量。这相当于一条线将所有购物车操作串联起来。采用官方推荐的响应式缓存和绑定框架管理购物车状态,能实现数据跨组件共享。每次操作购物车,都要同步更新状态。若处理不当,可能导致购物车数据显示错误等问题。

举个例子,过去有些类似的项目在数据状态管理上出了问题。当在两个页面同时操作购物车时,商品数量就变得混乱无序。

遇到空安全错误的解决

/// 加入购物车
void pushCart(CartInfoModel cartInfo) {
    // 查找 id/color/size 都相同的购物车商品
    int idx = cartList.indexWhere((item) => (item.id == cartInfo.id &&
        item.color == cartInfo.color &&
        item.size == cartInfo.size));
    if (idx > -1) {
      // 存在则数量+1
      cartList[idx].count += cartInfo.count;
    } else {
      // 不存在则添加(这里深拷贝cartInfo)
      cartList.add(cartInfoModelFromJson(cartInfoModelToJson(cartInfo)));
    }
    // 通知 CartNotifier 状态更新
    notifyListeners();
    // 更新数据存储到本地
    updCartPrefs();
}
/// 更新购物车数量
void updCartCount(CartInfoModel cartInfo, int count) {
    // 查找 id/color/size 都相同的购物车商品
    int idx = cartList.indexWhere((item) => (item.id == cartInfo.id &&
        item.color == cartInfo.color &&
        item.size == cartInfo.size));
    if (idx > -1) {
      // 存在则更新数量
      cartList[idx].count = count;
    }
    notifyListeners();
    // 更新数据存储到本地
    updCartPrefs();
}
/// 移除购物车指定商品
void renmoveCart(CartInfoModel cartInfo) {
    // 查找 id/color/size 都相同的购物车商品
    int idx = cartList.indexWhere((item) => (item.id == cartInfo.id &&
        item.color == cartInfo.color &&
        item.size == cartInfo.size));
    if (idx > -1) {
      // 存在则移除该项
      cartList.removeAt(idx);
    }
    notifyListeners();
    // 更新数据存储到本地
    updCartPrefs();
}

项目开发中,若采用v2版或以上,运行或打包时若出现空安全错误,通常是因为某些编写方式或插件未遵循空安全标准。这时,推荐更换支持空安全的插件。就像机器某个部件不匹配,无法运作,需找到合适的部件才能让机器正常运转。在开发过程中,若此类空安全错误未能及时处理,会延误项目进度。而且,这些错误可能潜藏在代码的各个部分,不易察觉。因此,对开发版本的特性需时刻保持警觉,并严格按照要求挑选插件。

在项目开发过程中,大家是否曾面临过挑选插件时的难题或是遇到空安全错误的问题?期待大家踊跃留言交流。若觉得这篇文章对您有帮助,不妨点赞并转发。

import 'package:shared_preferences/shared_preferences.dart';
class CartNotifier extends ChangeNotifier {
  final List<CartInfoModel> cartList = <CartInfoModel>[];
  ...
  
  /// 更新购物车数据到本地持久化存储
  
  void updCartPrefs() async {
    final prefs = await SharedPreferences.getInstance();
    // 购物车数据转为字符串
    String cartString = json.encode(cartList).toString();
    // `setString`存储到本地
    prefs.setString('cartList', cartString);
  }
  
  /// 查询/初始化 - 从本地读取数据恢复到购物车状态
  
  Future<List<CartInfoModel>> getCartList() async {
    // 获取持久化实例
    final prefs = await SharedPreferences.getInstance();
    // 调用`getString`方法读取本地字符串数据
    String? _cartString = prefs.getString('cartList');
    cartList.clear();
    // 字符串数据转换为`CartInfoModel`初始化到购物车列表
    if (_cartString != null) {
      List<CartInfoModel> _list = cartInfoModelListFromJson(_cartString);
      cartList.addAll(_list);
    }
    notifyListeners();
    return cartList;
  }
}

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

七爪网 行业资讯 Flutter 2商城App实战指南:全面支持Null safety,助你快速开发 https://www.7claw.com/2800583.html

七爪网源码交易平台

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务