flutter实战 | 从0搭建 企业级电商项目(一、创建项目、添加插件)

1,175 阅读3分钟

本系列可能会分好几段,从0开始搭建一个「电商项目」的APP出来。

该 APP 功能的思维导图:

图片alt

创建项目

我自己用的最新的flutter环境

创建步骤这里就不赘述了。

项目创建好后,删除main.dart无用代码,然后开始创建文件夹:

一共分为七个文件夹:

  • api:存放所有数据类
  • model:存放所有数据类
  • router:存放路由相关
  • style:存放所有的公共样式
  • utils:存放所有的工具类
  • views:存放所有页面
  • widgets:存放所有封装好的组件

添加插件

下面我们开始添加依赖。

插件 作用
flutter_localizations 国际化
flutter_swiper 轮播图
dio 网络请求
shared_preferences 本地存储
url_launcher 启动URL的插件
webview_flutter WebView插件
permission_handler 于系统权限
image_picker 选择本地相机图片
cached_network_image 图片缓存
video_player 视频播放控件
flutter_spinkit 加载动画
like_button 动画点赞
city_pickers 城市选择器
fluwx 微信sdk
barcode_scan 扫一扫二维码
photo_view 图片查看

项目共用代码

最常见的莫过于样式通用代码 /style 存放样式有关的通用代码

  • 颜色 colors.dart
class Colours {
  static const app_main = Color(0xFF4688FA);
  static const bg_color = Color(0xfff1f1f1);
}
  • 间隔 gaps.dart
class Gaps {
  /// 水平间隔
  static const Widget hGap4 = const SizedBox(width: 4.0);
  /// 垂直间隔
  static const Widget vGap2 = const SizedBox(height: 2.0);
}

最后整合起来导入到同一个文件 resources.dart,引用该文件即可,或者按需引入

export 'colors.dart';
export 'gaps.dart';

通用组件(类似前端组件,将一些复用性较强的封装成组件)
例如最基础的加载组件,弱提示组件,二次确认组件;
这里说一下二次确认组件开发的思想,flutter本身提供了showDialog方法,在此基础上进行自己的改造 之前开发过微信小程序,参考微信小程序的showModal思想,该组件提供颜色,文字,成功,失败回调;

void showTipDialog(context, {
  String title, 
  String content, 
  bool showCancel = true, 
  String cancelText = '取消', 
  Color cancelColor = const Color(0xFF000000),
  String confirmText = '确定',
  Color confirmColor = const Color(0xFF3233F3),
  VoidCallback success,
  VoidCallback fail,

}) {
  showDialog(
    // 传入 context
    context: context,
    // 构建 Dialog 的视图
    builder: (_) => Padding(
      padding: EdgeInsets.all(40),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.all(Radius.circular(12.0))
            ),
            child: Column(
              children: <Widget>[
                Gaps.vGap16, /// 横向分割块
                title != null ? Padding(
                  padding: EdgeInsets.only(top: 8, bottom: 8),
                  child: Text(title, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, decoration: TextDecoration.none, color: Colors.black)),
                ) : Container(),
                Container(
                  padding: EdgeInsets.only(top: 14, bottom: 30, left: 20, right: 20),
                  alignment: Alignment.center,
                  child: Text(content,textAlign: TextAlign.center, style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500, decoration: TextDecoration.none, color: Color(0xFF000000))),
                ),
                Gaps.line,
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    Expanded(
                      child: SizedBox(
                        height: 48.0,
                        child: FlatButton(
                          child: Text(
                            cancelText,
                            style: TextStyle(
                              fontSize: 15,
                              fontWeight: FontWeight.w600
                            ),
                          ),
                          textColor: cancelColor,
                          onPressed: (){
                            Navigator.pop(_);
                            fail();
                          },
                        ),
                      ),
                    ),
                    SizedBox(
                      height: 48.0,
                      width: 0.6,
                      child:  DecoratedBox(decoration: BoxDecoration(color: Colours.line)),
                    ),
                    Expanded(
                      child: SizedBox(
                        height: 48.0,
                        child: FlatButton(
                          child: Text(
                            confirmText,
                            style: TextStyle(
                              fontSize: 15,
                              fontWeight: FontWeight.w600
                            ),
                          ),
                          textColor: confirmColor,
                          onPressed: (){
                            Navigator.pop(context);
                            success();
                          },
                        ),
                      ),
                    )
                  ],
                )
              ],
            ),
          )
        ],
      ),
    ),
  );
}

调用方式(引入组件)

showTipDialog(
    context, /// 上下文,直接传build的 context
    content: '是否删除该地址?',
    confirmText: '删除地址',
    success: () {}, /// 成功回调
    fail: () {}, /// 失败回调
);

效果

项目截图

图片太多了 先放tab的截图

最后

该篇文章是当前系列的第一篇。 由于还在整理代码,更新之后上github地址