1-Flutter分享

Flutter简介

Flutter 是 Google 推出并开源的移动应用开发框架,帮助开发者通过一套代码库高效构建多平台应用,支持 iOS、Android、Web、Windows、macOS、Linux、Fuchsia

优点

  1. 跨平台:增加代码复用,降低开发成本
  2. 性能:Flutter直接将Dart代码编译为本地代码运行,再调用skia绘图引擎代码,和原生一样,这就少了像reactnative和weex等先转为原生控件,再系统渲染的步骤
  3. 热重载:修改完代码后 Ctrl+S 就能实时展现在真机界面上,不需要重新安装 apk 包,提高开发效率
    unknown_filename.3
    unknown_filename.4

Impeller

Impeller 是 Flutter 团队新开发的 **渲染引擎 (renderer)**,专门替代之前的 Skia 渲染管线

  • 目标是 更低的延迟、更流畅的动画、更稳定的性能
  • 特别是为了解决 iOS 上的 jank(掉帧卡顿) 问题。
对比点 Skia (旧) Impeller (新)
渲染管线 通用 2D 引擎(Skia) Flutter 专属优化管线
Shader 运行时编译 → 可能掉帧 预编译 shader,无需运行时编译
平台支持 OpenGL / Metal / Vulkan(跨平台) 目前主要支持 Metal (iOS)、Vulkan (Android 部分设备),逐步扩展
性能 动画掉帧可能性高,尤其在 iOS 更低延迟,几乎无 shader jank
稳定性 已经很成熟,但 Flutter 需要做额外适配 更适配 Flutter 绘制模型(比如曲线、图层合成等)
目标 通用图形库 专为 Flutter 设计的渲染后端
![[Pasted image 20250917102231.png]]

缺点

1.脱离不开原生,一些功能不支持,需要原生开发
2.适配问题,可能会有各种各样的适配问题
3.基础库不完善,需要自己写

在现阶段,开始尝试探索和积累沉淀 Flutter 技术能力,逐步的完善,flutter还是值得尝试一下的,毕竟研发效率就是竞争力。

现状

现在的很多 app 都有进行 flutter 的功能,这是“国内大厂应用在移动端 Flutter 框架使用分析”,地址链接:https://juejin.cn/post/7012382656578977806

常用网址

Flutter 开发文档

Flutter实战

Dart 编程语言概览

pub仓库

Widget

Activity、Fragment、view 在 Flutter 中等价于 Widget.

与 Android view 区别

  • Android 中 View 是可变的,当用户交互或数据更新时,可直接调用 View 的 invalidate 方法重绘,达到更新 UI 的目的。
  • Flutter 的 widget 是不可改变的因此不能直接更新,而必须使用 Widget 的状态。Flutter 的 widget 分为有状态和无状态两种。

Stateful widgets

Stateless widgets 是不可变的, 这意味着它们的属性不能改变,所有的值都是最终的.
Stateful widgets(有状态的部件) 持有的状态可能在 widget 生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

  1. 一个 StatefulWidget 类。
  2. 一个 State 类。 StatefulWidget 类本身是不变的,但是 State 类在 widget 生命周期中始终存在.

stateful widget 将自身的构建委托给 State 对象,State 对象的 build 函数负责构建该 Widget,当用户交互或数据发生变化时,Widget 状态发生改变,调用 State 的 setState 方法通知它,而后 State 根据当前的状态信息,重新构建 Widget tree

  • 在 Android 中,您可以从父级控件调用 addChild 或 removeChild 以动态添加或删除 View。在 Flutter 中,因为 widget 是不可变的,所以没有 addChild。相反,您可以传入一个函数,该函数返回一个 widget 给父项,并通过 布尔值控制该 widget 的创建
  • 在 Flutter 中,一个自定义 widget 通常是通过组合其它 widget 来实现的,而不是继承
  • 某些 widget 属性需要单个 widget(child),而其它一些属性,如 action,需要一组 widgets (children),用方括号[]表示。

生命周期

  • 初始化initState()
  • 依赖变化didChangeDependencies()
  • 构建 UIbuild()
  • 更新时机didUpdateWidget()
  • 销毁dispose()
    👉 一句话总结:
    StatefulWidget 生命周期 = initState → build → (setState → build 循环) → dispose

这里的重点是 StatefulWidget,因为 StatelessWidget 没有生命周期,只有一次 build。

Flutter 生命周期分层
在 Flutter 里,生命周期不是 Widget 本身,而是 State 对象的生命周期

  • Widget:描述 UI 的配置数据,不可变(immutable)。
  • Element:Widget 在 Widget Tree 里的位置表示,负责管理 Widget 和 RenderObject。
  • State:和 StatefulWidget 绑定,保存可变状态,生命周期由框架管理。

所以我们平时说的“生命周期”,其实就是 State 的生命周期

statefulWidget 的生命周期方法

创建阶段

  1. createState()

    • 在 StatefulWidget 创建时调用,只执行一次。
    • 返回一个 State 对象。
  2. initState()

    • 在 State 对象插入到树中时调用(只执行一次)。
    • 常用于初始化数据、订阅事件、启动动画。
    • ⚠️ 不能在这里调用 BuildContext 依赖 InheritedWidget 的东西(比如 Theme.of(context)),因为 State 还没完全挂到树上。

依赖变化阶段
didChangeDependencies()
- 在 initState() 之后立即调用一次。
- 当依赖的 InheritedWidget(如 Theme、Locale)发生变化时再次调用。
- 可以安全地使用 BuildContext

构建阶段
build(BuildContext context)
- Widget 的核心方法。
- 每次调用 setState(),都会重新执行 build(),重新构建 UI。
- ⚠️ 这里只应该做 UI 构建,避免耗时操作。

更新阶段
didUpdateWidget(covariant OldWidget oldWidget)
- 当父组件重建时,如果传给当前 Widget 的配置数据发生变化,会触发这个方法。
- 适合在这里比较新旧 Widget 的差异,并做相应更新。

销毁阶段
deactivate()
- 当 State 从树中移除时调用。
- 可能会再次插入树中(比如在 TabBar 切换时),所以不是最终销毁。

dispose()
- 当 State 被永久移除时调用。
- 用于释放资源:取消订阅、关闭 AnimationController、清理 Timer 等。
- ⚠️ 调用后,这个 State 就不再可用。

常用Widget和属性

  • Container:父 view,宽高、背景色、圆角、margin

  • Padding:EdgeInsets. fromLTRB

  • Center:居中

  • TextField:输入框(TextEditingController)

  • Expanded:填充剩余布局,组件有个参数 flex, 可以实现比例分配。
    height 如果不设置界面显示会有问题,如果要设置,又不能准确的计算出结果, 可以使用 Expanded

  • BoxDecoration: 圆角,需要放在 Container 里,实现边框、圆角、阴影、形状、渐变、背景图像

  • ShapeDecoration: 实现四个边分别指定颜色和宽度、底部线、矩形边色、圆形边色、体育场(竖向椭圆)、角形(八边角)边色

  • UnderlineTabindicator: 下划线

  • EdgeInsets. only
    symmetric ({vertical, horizontal}):用于设置对称方向的填充,vertical 指 top 和 bottom,horizontal 指 left 和 right。

  • Flutter 中官方提供 CustomScrollView,让我们能够作何 Appbar 折叠的效果,并且很容易就能实现下拉刷新和加载更多。

  • dialog 高度设置不生效将 showBottomsheet 更换成 showAdjustableBottomSheet

  • MediaQuery. removePadding 可以移除组件的边距,有些组件自带有边距

  • expenand 必须和 colum 或 row 一起用,否则 debug 能运行,release 报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
RichText(text: TextSpan(
children: [
TextSpan(
text:"*",
style: TextStyle(color: Color.colorAuxRedColor, fontSize: 15)
),
TextSpan(
text:"你好",
style: TextStyle(color: Color.colorText222Color, fontSize: 15)
)
]
)),



Visibility(
visible: true,
//是否保持占位
maintainState: false,
child: Text("显示"),
),

unknown_filename.6

点击

  • 在 Flutter 中,添加触摸监听器有两种方法: 如果 Widget 支持事件监听,则可以将一个函数传递给它并进行处理。例如,RaisedButton 有一个 onPressed 参数
  • 如果 Widget 不支持事件监听,则可以将该 Widget 包装到 GestureDetector 中,并将处理函数传递给 onTap 参数。
  • InkWell:点击,和 GestureDetector区别,即使 InkWell 没有子控件,它仍然可以响应点击操作并执行相应的操作或触发回调函数。

MaterialApp

MaterialApp 是我们使用 Flutter 开发中最常用的符合 Material Design 设计理念的入口 Widget。你可以将它类比成为网页中的,且它自带路由、主题色,<\title>等功能。

listView  
CustomScrollView 
ScrollView
SingleChildScrollView

Scaffold

Scaffold 翻译过来就是 “脚手架”,在 Flutter 里它是一个 Material Design 风格的页面框架容器

  • 提供一个标准页面的结构(AppBar、Drawer、BottomNavigationBar、FloatingActionButton、SnackBar 等)。
  • 你只需要把页面主体内容 (body) 填进去,就能很快得到一个完整的 Material 风格页面。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const Scaffold({
Key key,
this.appBar, // 标题栏
this.body, // 用于显示当前界面主要内容的Widget
this.floatingActionButton, // 一个悬浮在body上的按钮,默认显示在右下角
this.floatingActionButtonLocation, // 用于设置floatingActionButton显示的位置
this.floatingActionButtonAnimator, // floatingActionButton移动到一个新的位置时的动画
this.persistentFooterButtons, // 多状态按钮
this.drawer, // 左侧的抽屉菜单
this.endDrawer, // 右'侧的抽屉菜单
this.bottomNavigationBar,// 底部导航栏。
this.bottomSheet, // 显示在底部的工具栏
this.backgroundColor,// 内容的背景颜色
this.resizeToAvoidBottomPadding = true, // 控制界面内容 body 是否重新布局来避免底部被覆盖,比如当键盘显示的时候,重新布局避免被键盘盖住内容。
this.primary = true,// Scaffold是否显示在页面的顶部
})

SizedBox

  • 一般是用来限制孩子控件的大小。
  • 还有这么一种场景也可以使用SizeBox,就是可以代替padding和container,然后 用来设置两个控件之间的间距,比如在行或列中就可以设置两个控件之间的间距 主要是可以比使用一个padding或者container简单方便 (在Flutter中可能用不同的控件可以实现到相同的目的,尽量使用越简单的widget来实现)
  • 控件在整个手机屏幕中间对齐:ConstrainedBox、SizedBox、Center

布局

Flutter 中通过 Row 和 Column 来实现线性布局,类似于 Android 中的 LinearLayout 控件
row 水平,Column 竖直

  • 对于线性布局,有主轴和纵轴之分,如果布局是沿水平方向,那么主轴就是指水平方向,而纵轴即垂直方向;如果布局沿垂直方向,那么主轴就是指垂直方向,而纵轴就是水平方向。在线性布局中,有两个定义对齐方式的枚举类 MainAxisAlignment 和 CrossAxisAlignment,分别代表主轴对齐和纵轴对齐。
  • mainAxisSize:表示 Row 在主轴 (水平) 方向占用的空间,默认是 MainAxisSize. max,表示尽可能多的占用水平方向的空间,此时无论子 widgets 实际占用多少水平空间,Row 的宽度始终等于水平方向的最大宽度;
  • 而 MainAxisSize. min 表示尽可能少的占用水平空间,当子组件没有占满水平剩余空间,则 Row 的实际宽度等于所有子组件占用的的水平空间
  • Row 和 Column 都只会在主轴方向占用尽可能大的空间,而纵轴的长度则取决于他们最大子元素的长度
  • 如果 Row 里面嵌套 Row,或者 Column 里面再嵌套 Column,那么只有最外面的 Row 或 Column 会占用尽可能大的空间,里面 Row 或 Column 所占用的空间为实际大小 [[3-Flutter工作tips#约束]]

Stack 类似 FrameLayout 很像,都是可以叠加的现实 View
flutter 中默认组件尺寸单位都是dp
double. infinity,可以使宽度占用尽可能多的空间

当我们使用行(row)的时候,子组件常常因为高度的不同,导致各个子组件里面的内容不能对齐。这个时候我们可以使用 IntrinsicHeight 来保持 row 中各个子组件高度一致,从而便于纵向居中对齐。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum MainAxisAlignment {
//将子控件放在主轴的开始位置
start,
//将子控件放在主轴的结束位置
end,
//将子控件放在主轴的中间位置
center,
//将主轴空白位置进行均分,排列子元素,手尾没有空隙
spaceBetween,
//将主轴空白区域均分,使中间各个子控件间距相等,首尾子控件间距为中间子控件间距的一半
spaceAround,
//将主轴空白区域均分,使各个子控件间距相等
spaceEvenly,
}

Dart语法

main函数使用了(=>)符号, 这是Dart中单行函数或方法的简写。

1
2
// =>是return语句的简写
add3(a, b) => a + b;

变量以下划线(_)开头,在Dart语言中使用下划线前缀标识符,会强制其变成私有的。

异步

[[5-线程异步多订阅]]

JSON 转 Bean

自动生成实体类

1
2
3
4
5
6
7
8
9
{
"greeting": "Welcome to quicktype!",
"instructions": [
"Type or paste JSON here",
"Or choose a sample above",
"quicktype will generate code in your",
"chosen language to parse the sample data"
]
}

fromJson map 转对象
toJson 对象转 map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import 'dart:convert';

Welcome welcomeFromJson(String str) => Welcome.fromJson(json.decode(str));

String welcomeToJson(Welcome data) => json.encode(data.toJson());

class Welcome {
String greeting;
List<String> instructions;

Welcome({
required this.greeting,
required this.instructions,
});

factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
greeting: json["greeting"],
instructions: List<String>.from(json["instructions"].map((x) => x)),
);

Map<String, dynamic> toJson() => {
"greeting": greeting,
"instructions": List<dynamic>.from(instructions.map((x) => x)),
};
}

其他

状态管理框架

[[2-Flutter 状态管理框架]]

集成成 Android 项目:

android:exported=”true”

  1. flutter create -t module flutter_module
  2. 打开 android 项目 settings. gradle,将
    module 才有这个文件:include_flutter. groovy
1
2
3
4
5
6
rootProject.name = "NativeInFlutter"
include ':app'
include ':flutter_module'
setBinding(new Binding([gradle: this]))
evaluate(new File(settingsDir.parentFile, 'NativeInFlutter/flutter_module/.android/include_flutter.groovy'
))

这也得改 allprojects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.0"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
  1. app 下 build 加:implementation project (‘: flutter’)

项目如何使用

flutter仓库地址:
代码clone到与Android工程同级目录

Android目前有两种依赖方式:
本地依赖(适用于开发调试阶段)
配置文件repo_projects.xml中,打开下面这行

1
<project name="publication/app_ta_flutter.git" path="app_ta_flutter" />

远程依赖(适用打包或flutter功能稳定阶段)
配置repo_projects.xml中,注释下面这行

1
<project name="publication/app_ta_flutter.git" path="app_ta_flutter" />

打包

开发完后,提测或者上线,需要将 flutter 代码打包。目前已经支持了 jenkins 上自动打包 flutter,上传 maven,然后修改配置仓库,增加版本号,接着 push 代码,自动化打包。

jenkins打包地址:http://10.14.200.4:8880/jenkins_app/view/图书出版/job/android/job/lib/job/app_ta_flutter/build?delay=0sec

红框必选,其他不用写,选择完后点build
BUSINESS_BRANCH:选自己的开发的flutter功能对应的分支
PROPERTIES_BRANCH:要更新到哪个配置仓库的分支
unknown_filename.9

调试

先把 APP 杀死,在启动过程中 attach,可以先点这个

unknown_filename
出现下面这个就可以调试了
unknown_filename.1

使用‘尾随逗号’

Flutter代码通常涉及构建相当深的树状数据结构,例如在一个build方法中。 为了获得良好的自动格式化,我们建议您采用可选的尾部逗号。添加尾随逗号很简单:始终在函数、方法和构造函数的参数列表末尾添加尾随逗号,以便保留您的编码格式。 这将有助于自动格式化程序为Flutter样式代码插入适当的换行符。
unknown_filename.2

两个好用的图片插件

FlutterQuickLocateAsset
FlutterAssetAutoCompletion

使用自定义模板

提高开发效率
unknown_filename.8
unknown_filename.7


1-Flutter分享
http://peiniwan.github.io/2025/12/5a1b7f6ccf87.html
作者
六月的雨
发布于
2025年12月16日
许可协议