# Flutter项目分享

使用Flutter技术实现原生 合伙人项目 (opens new window)的全部功能,通过新技术学习更加深入理解flutter移动端UI跨平台方案存在的优缺点,对未来新项目的技术方向提供新的实现手段,项目按以下五个方面进行简单分类梳理

# 一、工程结构

  • # pubspec.yaml 文件

    SDK环境版本、资源目录、第三方库(Flutter pub)

  • # assets

    资源库;如图片资源:assets/images/

  • # External Libraries

    Dart Package 查看Flutter SDK和第三库源码;

    Flutter Plugins 插件库源码;

    ... 其它

  • # androidios

    应用ID、版本、打包等配置

    自定义插件

    使用权限

    UI启动初始化

    原生第三方库

  • # test

    测试普通函数

    test("金额格式化", () {
        
    }
    /// ... group 组合不同条件
    

    测试Widgets

    testWidgets('登录UI功能', (WidgetTester tester) async {
        
    }
    
  • # lib 业务结构
lib
├── data
│   ├── account
│   │   └── token_controller.dart
│   ├── entity
│   │   ├── util
│   │   ├── token.dart
│   │   └── version.dart
│   └── user_controller.dart
├── generated
│   └── json
│       ├── base
│       ├── token_helper.dart
│       └── version_helper.dart
├── io
│   ├── client
│   │   └── client.dart
│   ├── exception
│   │   └── api_exception.dart
│   ├── response
│   │   └── reponse_result.dart
│   ├── error_code.dart
│   ├── http_dio.dart
│   └── params.dart
├── plugin
│   └── mmm_flutter_plugin.dart
├── repository
│   ├── api
│   │   ├── api_common.dart
│   │   └── api_partner.dart
│   ├── account_repository.dart
│   └── partner_repository.dart
├── ui
│   ├── global_store
│   │   ├── action.dart
│   │   ├── reducer.dart
│   │   ├── state.dart
│   │   └── store.dart
│   ├── login
│   │   ├── action.dart
│   │   ├── effect.dart
│   │   ├── page.dart
│   │   ├── reducer.dart
│   │   ├── state.dart
│   │   └── view.dart
├── app.dart
├── global.dart
├── global_stream.dart
└── main.dart

# 二、项目使用第三方库

dependencies:
  dio: ^3.0.9            # 网络请求库
  event_bus: ^1.1.1      # 事件通知订阅
  fish_redux: ^0.3.4     # 基于 Redux 数据管理的组装式 flutter 应用框架
  uuid: ^2.0.4                     # UUID
  synchronized: ^2.2.0+2           # 同步锁
  device_info: ^0.4.2+4            # 获取设备信息
  package_info: ^0.4.1             # 获取应用包信息
  shared_preferences: ^0.5.8       # 简单数据持久存储
  flutter_spinkit: ^4.1.2          # 加载指示器
  flutter_datetime_picker: ^1.4.0  # 时间选择器
  permission_handler: ^5.0.1+1     # 系统权限
  date_format: ^1.0.8              # 日期时间格式化
  ...

JSON转换使用插件 JsonToDartBeanAction 进行生成(最好第一次使用,后续对象尽可能手动添加,插件存在BUG);

# 三、应用框架

# 主流框架

Scoped Model、BLoC (Business Logic Componet)、Provide、Redux、Fish_Redux;

# fish_redux

Redux 是一个专注于状态管理的框架;Fish Redux 是基于 Redux 做状态管理的应用框架。

应用框架不仅仅要解决状态管理的问题,还要解决分治,通信,数据驱动,解耦等等问题。

常用的几个对象概念:

  • Action

    用来定义在这个页面中发生的动作,例如:登录,清理输入框,更换验证码框等;

    可以通过payload参数传值;

  • Effect

    处理副作用操作的,比如显示弹窗,网络请求,数据库查询等操作;

  • Reducer

    用来更新View,通过创建新State进行更新View状态;

  • Page

    注册的路由页面,同时完成注册effect,reducer,component,adapter的功能;

  • State

    用来定义页面中的数据(属性),用来保存页面状态和数据;

  • View

    展示给用户看到的页面;

  • Adapter

    面向 ListView 场景的分治设计 Adapter

    # StaticFlowAdapter 接受 Object|Map 的数据驱动,模版接收一个 Dependent 的数组,每一个 Dependent 可以是 Component 或者 Adapter + Connector<T,P> 的组合。
    class ItemBodyComponent extends Component<ItemBodyState> {
        ItemBodyComponent()
            : super(
                view: buildItemBody,
                dependencies: Dependencies<ItemBodyState>(
                adapter: StaticFlowAdapter<ItemBodyState>(
                    slots: <Dependent<ItemBodyState>>[
                        VideoAdapter().asDependent(videoConnector()),
                        UserInfoComponent().asDependent(userInfoConnector()),
                        DescComponent().asDependent(descConnector()),
                        ItemImageComponent().asDependent(itemImageConnector()),
                        OriginDescComponent().asDependent(originDescConnector()),
                    ]),
                ),
            );
    }
    
    # DynamicFlowAdapter 模版是一个 Map,接受一个数组类型的数据驱动;
    class RecommendAdapter extends DynamicFlowAdapter<RecommendState> {
        RecommendAdapter()
            : super(
                pool: <String, Component<Object>>{
                    'card_0': RecommendTitleComponent(),
                    'card_1': RecommendRowComponent(),
                },
                connector: RecommendCardListConnector(),
            );
    }
    

# 四、页面路由

# 下面3种写法效果是一致的;
  1. Navigator.pushNamed(context, routeName, arguments)

  2. Navigator.of(context).pushNamed(routeName, arguments)

  3. Navigator.push(BuildContext context, Route<T> route)

# 参数:context上下文环境,routeName路由名称,arguments传递参数
# 使用:
  • # pushNamed,跳转到新页面
  • # pushReplacementNamed,当前页面替换成新页面
    • 案例:A-B-C,在 C-D 过程时调用该函数,A-B-D
  • # pushNamedAndRemoveUntil,跳转到新页面,对先前的路由,依据predicate条件判断,返回true为止,false 继续pop出栈;
    • 案例:A-B-C-D,在 D-E 过程时,想移除B、C, 最终栈顺序为 A-D-E,就可使用该函数;
  • # pop,退出当前页面
  • # popUntil,连续出栈,依据predicate条件判断,返回true为止,false 继续pop出栈;
    • 案例:A-B-C-D,想达到D-A的效果,可以使用该函数;
  • # popAndPushNamed,退出当前页面,跳转到新页面
    • 案例:A-B-C,在 C-D 过程时调用该函数,最终栈顺序 A-B-D;

# 五、常见问题

  • # RIGHT/BOTTOM PVERFLOWED BY xxx PIXELS

    Row、Column 布局中时出现超出屏幕范围时, 大部分用 Expanded 嵌套即可解决;

最后更新时间: 11/24/2021, 4:01:41 AM