欢迎、引导 登录、注册 主页
从 Flutter 2.0 开始学 - Widget 组件化 - 图1 从 Flutter 2.0 开始学 - Widget 组件化 - 图2 从 Flutter 2.0 开始学 - Widget 组件化 - 图3

组件化

组件化编程就像是搭积木一样的开发。把整个应用拆分成许多部分,每部分各自管理自己的组件以及数据状态,这样达到一个更好的可维护性,可扩展性。

组件类型

展示组件

  • 展示型组件并不维护数据状态,它更多的作用是用来展示效果与数据。

容器组件

  • 容器组件并不涉及 UI 方面,而是负责处理数据与状态。

布局组件

  • 特定的布局方式,建议是把它们封装成一个布局组件。

页面组件

  • 页面组件负责当前页面的组件结构。

Flutter Widget

在 Flutter 中,Widget 大体分为两种

StatelessWidget

无状态组件,至始至终都不需要改变

StatefulWidget

有状态组件,需要根据状态改变而改变,根据状态展示

栗子

在构建一个登录、注册界面时,分析整体界面布局,发现有些样式基本上是一致的,只不过显示文案不一样,通常情况下,可以把它们封装成一组通用组件,传递属性控制其显示。

  • 登录按钮、注册按钮
  • 账号输入框、密码输入框
  • 社交登录展示
  • 这些组件在显示上是一致的,样式不一致,这样可以封装成组件,可以复用

按钮、输入框、社交登录按钮

从 Flutter 2.0 开始学 - Widget 组件化 - 图4

从 Flutter 2.0 开始学 - Widget 组件化 - 图5

从 Flutter 2.0 开始学 - Widget 组件化 - 图6

Flutter Svg 图片使用

  • 使用第三方模块 flutter_svg

  • pubspec.yaml 添加依赖

  1. flutter_svg:
  2. git:
  3. url: git://github.com/gskinnerTeam/flutter_svg.git
  4. ref: 12b55b464d2e253f411a17798527a7daa2c00ceb

SvgPicture API 调用

  • 基本使用
  1. SvgPicture.asset(iconSrc, height: 60.w, width: 60.w)
  • SvgPicture.asset 可以加载显示一张 svg 图
  • SvgPicture 更丰富 API 可以查看其文档

按钮封装

创建一个 widgets 包,专门用来放 app 组件

  • 在 widgets 目录下也可以根据不同业务划分不同的组件;

    • 比如登录、注册… 用来授权的界面组件,可以创建一个 auth 包
    • 比如订单模块用到的组件,可以创建 order 包
    • 通用的组件可以创建 common 包
    • 具体划分需要根据 app 实际场景来做

创建 auth_button.dart

widgets -> auth -> auth_button.dart

命名 ATHAuthButton

  • ATH 前缀,具体可根据项目名称或公司规则
  1. class ATHAuthButton extends StatelessWidget {
  2. // 按钮显示文本
  3. final String text;
  4. // 点击事件
  5. final Function press;
  6. // 显示样式(颜色)
  7. final Color color, textColor;
  8. const ATHAuthButton({
  9. Key key,
  10. this.text,
  11. this.press,
  12. this.color = kPrimaryColor,
  13. this.textColor = Colors.white,
  14. }) : super(key: key);
  15. @override
  16. Widget build(BuildContext context) {
  17. return Container(
  18. // 设置边距
  19. // 24.w 16.w 使用 flutter_screenutil 模块提供的屏幕适配,
  20. // dart sdk>=2.6 版本扩展语法
  21. margin: EdgeInsets.symmetric(horizontal: 24.w, vertical: 16.w),
  22. // 宽度 double.infinity 表示撑满整个手机屏幕宽度
  23. width: double.infinity,
  24. // ClipRRect 可以裁截,设置圆角
  25. child: ClipRRect(
  26. borderRadius: BorderRadius.circular(16.w),
  27. // TextButton flutter 2.0 版本中新组件
  28. child: TextButton(
  29. onPressed: press,
  30. // 按钮样式
  31. style: ButtonStyle(
  32. padding: MaterialStateProperty.all(
  33. EdgeInsets.symmetric(vertical: 20.h)),
  34. backgroundColor: MaterialStateProperty.all(color)),
  35. child: Text(
  36. text,
  37. style: TextStyle(
  38. color: textColor,
  39. fontWeight: FontWeight.bold,
  40. fontSize: 28.sp
  41. ),
  42. ),
  43. ),
  44. ),
  45. );
  46. }
  47. }

社交按钮

  • 创建 social_icons.dart
  1. class ATHSocialIcon extends StatelessWidget {
  2. // 图片
  3. final String iconSrc;
  4. // 按钮事件
  5. final Function press;
  6. const ATHSocialIcon({
  7. Key key,
  8. this.iconSrc,
  9. this.press,
  10. }) : super(key: key);
  11. @override
  12. Widget build(BuildContext context) {
  13. return GestureDetector(
  14. onTap: press,
  15. child: Container(
  16. margin: EdgeInsets.symmetric(horizontal: 16.h),
  17. padding: EdgeInsets.all(16.w),
  18. decoration: BoxDecoration(
  19. border: Border.all(width: 2.w, color: kPrimaryLightColor),
  20. shape: BoxShape.circle,
  21. ),
  22. // 使用
  23. child: SvgPicture.asset(iconSrc, height: 60.w, width: 60.w),
  24. ),
  25. );
  26. }
  27. }

输入框封装

Flutter 输入框组件 TextField,输入框组件提供了可以输入能力

栗子: 账号输入框

创建 auth_account_input.dart

  1. import 'auth_text_field_wrap.dart';
  2. class ATHAuthAccountInput extends StatelessWidget {
  3. final String hintText;
  4. // 输入框前缀图片
  5. final IconData icon;
  6. // 监听输入改变事件
  7. final ValueChanged<String> onChanged;
  8. // 输入控制器
  9. final TextEditingController controller;
  10. const ATHAuthAccountInput({
  11. Key key,
  12. this.hintText,
  13. this.icon = Icons.person,
  14. this.controller,
  15. this.onChanged,
  16. }) : super(key: key);
  17. @override
  18. Widget build(BuildContext context) {
  19. return ATHAuthTextFieldWrap(
  20. child: TextField(
  21. onChanged: onChanged,
  22. controller: controller,
  23. decoration: InputDecoration(
  24. icon: Container(
  25. padding: EdgeInsets.only(left: 16.w),
  26. child: Icon(
  27. Icons.people,
  28. color: kPrimaryColor,
  29. ),
  30. ),
  31. hintText: hintText,
  32. border: InputBorder.none,
  33. ),
  34. ),
  35. );
  36. }
  37. }
  • InputDecoration 修饰输入框边框样式

ATHAuthTextFieldWrap

  • 该组件只是为了统一边距
  • 也可以省略该组件,设置其使用父容器边距即可
  1. class ATHAuthTextFieldWrap extends StatelessWidget {
  2. final Widget child;
  3. const ATHAuthTextFieldWrap({
  4. Key key,
  5. this.child,
  6. }) : super(key: key);
  7. @override
  8. Widget build(BuildContext context) {
  9. return Container(
  10. margin: EdgeInsets.symmetric(horizontal: 24.w, vertical: 20.h),
  11. width: double.infinity,
  12. decoration: BoxDecoration(
  13. color: kPrimaryLightColor,
  14. borderRadius: BorderRadius.circular(16.w),
  15. ),
  16. child: child,
  17. );
  18. }
  19. }