Android 主要概念与 Flutter 对应关系
主要概念 | 在 Android 中 | 在 Flutter 中的对应 |
---|---|---|
页面 | Activity / Fragment |
Widget (通常是 StatefulWidget ) |
视图 | View |
Widget (StatelessWidget 或 StatefulWidget ) |
页面跳转 | Intent |
Navigator / Route |
网络库 | OkHttp 、Retrofit |
http 、dio 等 |
数据存储 | SharedPreferences 、SQLite |
shared_preferences 、sqflite 、hive |
1. 页面(Activity / Fragment ↔ Widget)
关键点 | Android | Flutter |
---|---|---|
生命周期 | onCreate → onStart → onResume ... |
initState → build → dispose |
页面栈管理 | 系统 Back Stack |
Navigator 内部堆栈 |
UI 组合 | XML 布局嵌套 ViewGroup |
小部件树(Widget Tree) |
思考 :在 Flutter 中,一个完整屏幕通常由一个
StatefulWidget
充当"Activity",而局部区域可用多个子 Widget 类似"Fragment"进行组合。
2. 视图(View ↔ Widget)
-
自定义控件
- Android :继承
View
并覆写onDraw
- Flutter :组合基础 Widget 或通过
CustomPainter
绘制
- Android :继承
-
响应式更新
- Flutter 的 Widget 是 不可变 对象,状态变更触发重新构建;与 Android
View
的"属性改变即生效"有所不同。
- Flutter 的 Widget 是 不可变 对象,状态变更触发重新构建;与 Android
3. 页面跳转(Intent ↔ Navigator)
操作 | Android | Flutter |
---|---|---|
启动新页 | startActivity(Intent) |
Navigator.push(context, route) |
返回上一页 | finish() /系统返回键 |
Navigator.pop(context) |
携带参数 | Intent.putExtra() |
构造 Route 时传参或使用 settings |
路由管理库 :Flutter 可使用
go_router
、auto_route
获得更声明式的导航体验,类似 Android Jetpack Navigation。
4. 网络请求(OkHttp ↔ http / dio)
- 简单场景 :
http
包封装了get/post
,相当于最轻量版 OkHttp。 - 复杂需求 :
dio
支持拦截器、队列调度、全局配置,与 Android 的 OkHttp + Retrofit 组合功能接近。 - 序列化 :Flutter 常配合
json_serializable
、freezed
;Android 常用 Gson/Moshi、Kotlinx.serialization。
5. 数据存储(SharedPreferences / SQLite ↔ shared_preferences / sqflite)
数据规模 | Android | Flutter |
---|---|---|
键值对 | SharedPreferences |
shared_preferences |
关系型 | SQLite (Room ORM) |
sqflite 、drift ORM |
轻量非关系型 | --- | hive (纯 Dart 无平台通道,性能优) |
Flutter 端若需与原生共享数据,可通过平台通道调用 Android
SharedPreferences
或 iOSNSUserDefaults
。
小结
- Flutter 把所有 UI 概念统一为 Widget,比 Android 视图层级更一致;
- 生命周期、导航与状态管理是学习迁移的主要难点;
- 原生常用库(网络、存储)在 Flutter 中都有成熟替代品,并通常以社区 pub 包的形式提供。
掌握上述映射后,Android 开发者可更快转向 Flutter 并解决常见业务需求。
相关布局对应关系
主要概念 | 在 Android 中 | 在 Flutter 中的对应 |
---|---|---|
布局文件 | XML |
直接用 Dart 代码声明 Widget 树 |
线性布局 | LinearLayout |
Row 与 Column |
相对布局 | RelativeLayout |
组合 Column 、Row 、Stack (必要时配合 Align / Positioned ) |
文本框 | TextView |
Text |
输入框 | EditText |
TextField |
1. 布局文件:XML ↔ Widget 树
- Android :先写 XML,再在 Java/Kotlin 中
findViewById()
。 - Flutter :UI 与逻辑统一在 Dart,采用声明式 方式,
build()
每次状态变更都会重新构建 Widget 树。 - 优势对比:Flutter 避免重复查找控件,UI 更新全靠状态驱动,减少手动刷新。
2. 线性布局:LinearLayout ↔ Row / Column
维度 | Android | Flutter |
---|---|---|
方向 | `android:orientation="vertical | horizontal"` |
权重 | layout_weight |
Expanded / Flexible |
对齐 | gravity |
mainAxisAlignment 、crossAxisAlignment |
实践 :绝大多数线性嵌套场景,可通过多层
Row
、Column
或Flex
实现,灵活使用Expanded
处理权重占比。
3. 相对布局:RelativeLayout ↔ Stack + 组合
-
RelativeLayout 用于"谁在谁旁边/下方" 相对定位;
-
Flutter 常用:
Stack
负责层叠;Positioned
/Align
确定相对父级的位置;- 或在多层
Row
/Column
中穿插Spacer
、Expanded
达到同类效果。
-
新手技巧 :先用
Column
+Row
拼到最近似,再局部用Stack
叠加角标/悬浮按钮。
4. 文本与输入
组件 | Android | Flutter | 补充 |
---|---|---|---|
文本 | TextView |
Text |
通过 style 或 TextStyle 设置字体、颜色、行距。 |
输入框 | EditText |
TextField / TextFormField |
表单验证时优先用 TextFormField ,可配合 Form 和 GlobalKey 。 |
5. 约束与权重替代方案
- Android ConstraintLayout 在 Flutter 中可用 第三方
flutter_constraintlayout
,但官方更推荐 declarative 布局思想,通过组合 Widgets 达到约束效果。 - 布局权重用
Expanded
/Flexible
;尺寸适配可用FractionallySizedBox
、LayoutBuilder
。
小结
- Flutter 把布局拆成更细粒度 Widgets ,大量场景下只需灵活堆叠
Row
、Column
、Stack
即可覆盖 Android 大部分布局需求。 - 声明式 UI 让状态变化 → 触发
build()
→ 自动刷新界面,避免手动调用invalidate()
/requestLayout()
。 - 熟悉这些映射后,Android 开发者可快速上手 Flutter,并在实际项目中选择最贴合的 Widget 组合完成界面搭建。
滚动列表对应关系
主要概念 | 在 Android 中 | 在 Flutter 中的对应 |
---|---|---|
布局文件 | XML |
直接用 Dart 声明 Widget 树 |
滚动视图 | ScrollView |
ListView (或 SingleChildScrollView ) |
列表(静态) | ListView |
ListView |
列表(高效复用) | RecyclerView |
ListView.builder (或 SliverList + CustomScrollView ) |
1. 布局文件:XML ↔ Widget
- Android :UI 写在 XML,逻辑写在 Java/Kotlin,需要
findViewById()
或 ViewBinding。 - Flutter:UI 与逻辑统一在 Dart;状态变化会重建 Widget 树,无需手动刷新。
2. 滚动视图:ScrollView ↔ ListView / SingleChildScrollView
维度 | Android ScrollView |
Flutter 对应 |
---|---|---|
适用场景 | 只有单个直接子元素(再嵌套多层) | SingleChildScrollView (单子组件)或 ListView (多子组件) |
惯性滚动 | 内置 | 内置(可配置 physics ) |
嵌套滚动 | 需搭配 NestedScrollView |
NestedScrollView / CustomScrollView + Sliver |
若要展示同构 item 列表,Flutter 更推荐直接使用
ListView
。
3. ListView:静态 vs. 动态
-
Android
ListView
- 传统 Adapter +
convertView
复用;性能一般,已逐步被RecyclerView
取代。
- 传统 Adapter +
-
Flutter
ListView
-
静态模式 :直接传
children
列表,适合数量有限的 item。 -
动态/懒加载模式:
ListView.builder
:按需构建,可无限列表。ListView.separated
:支持分隔符。- 带分组的可用
SliverList
+SliverGroupBuilder
等高级组合。
-
4. RecyclerView ↔ ListView.builder / Sliver 系列
特性 | Android RecyclerView |
Flutter ListView.builder |
---|---|---|
视图复用 | ViewHolder 缓存复用 |
Flutter 内部 Sliver 渲染管线自动复用 Element & RenderObject |
布局管理 | LayoutManager 控制方向/网格/瀑布流 |
方向用 scrollDirection ,网格用 GridView.builder ,瀑布流第三方库 flutter_staggered_grid_view |
Item 动画 | ItemAnimator |
implicit_animations 、AnimatedList 、SliverAnimatedList |
差分刷新 | DiffUtil |
借助状态管理(setState/Provider)+ AnimatedSwitcher / ListView.builder 自动对比 |
高级 Sliver:
CustomScrollView
+SliverList / SliverGrid / SliverAppBar
可实现折叠头、Sticky Header、吸顶 Tab 等复杂滚动效果,功能与 AndroidCoordinatorLayout
+AppBarLayout
+RecyclerView
类似。
5. 常见开发迁移要点
- 布局思维转变:告别 XML + Adapter,拥抱声明式 UI 和按需构建。
- 性能优化 :Flutter 已默认做了视图缓存和滑动合成,只需关注 item 数量及图片加载(可配合
cached_network_image
)。 - 嵌套列表 :
NestedScrollView
+SliverList
解决滚动冲突,等价于 Android 的NestedScrollView
+RecyclerView
。 - 状态管理 :在 Flutter 中列表刷新主要依赖
setState
、Provider
、Riverpod
等状态框架,而非 Adapter 通知。
小结
ScrollView / ListView / RecyclerView
在 Flutter 中统一归于Scrollable
➜Viewport
➜Sliver
渲染体系,开发者通过 不同构造函数 (children
、builder
) 或 不同 Widget (ListView
、GridView
、CustomScrollView
) 来选择最合适实现。- 对 Android 开发者而言,理解 懒加载(builder) 、Sliver 及 声明式刷新 是迁移滚动列表的关键。
快速收手布局开发
如何更新(布局)widgets?
Flutter 中最常见的布局刷新方式------StatefulWidget + setState()
。
1️⃣ 关键思路
- 把会变化的数据(这里是颜色)放到
State
中。 - 在手势或逻辑回调里修改数据,一定包在
setState()
内。 setState()
会触发框架重新执行build()
,从而刷新界面。
2️⃣ 完整示例(main.dart
)
dart
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '更新 Widget 示例',
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
home: const ColorSwitcherPage(),
);
}
}
/* ------------------- StatefulWidget ------------------- */
class ColorSwitcherPage extends StatefulWidget {
const ColorSwitcherPage({super.key});
@override
State<ColorSwitcherPage> createState() => _ColorSwitcherPageState();
}
class _ColorSwitcherPageState extends State<ColorSwitcherPage> {
// ① 可变数据:当前卡片颜色
Color _cardColor = Colors.indigo;
// ② 点击时随机换色
void _changeColor() {
setState(() {
_cardColor =
// 随机生成一个颜色(演示用)
Color((0xFF << 24) | (0xFFFFFF & DateTime.now().millisecondsSinceEpoch));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('setState() 刷新布局')),
body: Center(
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: _cardColor,
borderRadius: BorderRadius.circular(16),
),
alignment: Alignment.center,
child: const Text(
'点按钮换色',
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _changeColor, // ③ 更新状态 → 触发重建
child: const Icon(Icons.refresh),
),
);
}
}
代码要点
步骤 | 说明 |
---|---|
① 定义状态 | _cardColor 存放当前背景颜色。 |
② 修改状态 | _changeColor() 中用 setState() 包裹赋值操作。 |
③ 触发刷新 | FloatingActionButton 点击时调用 _changeColor() ;setState() ➜ Flutter 重新调用 build() ➜ 看到新颜色。 |
如何在布局中添加或删除一个 widget?
不同于Android,Flutter没有add 和 remove的方法用来动态添加和删除视图,只能通过替换的方式。下边的例子页面只有一段文字和一个按钮 点击按钮可在"显示 / 隐藏"之间切换 ------ 相当于 在布局中动态添加或删除这段文字。
scala
dart
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: ToggleTextDemo()));
class ToggleTextDemo extends StatefulWidget {
const ToggleTextDemo({super.key});
@override
State<ToggleTextDemo> createState() => _ToggleTextDemoState();
}
class _ToggleTextDemoState extends State<ToggleTextDemo> {
bool _showText = true; // 是否显示文本
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('添加 / 删除 Widget(简版)')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (_showText) // ① 条件渲染
const Text('👋 你好,我会被添加或删除'),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => // ② setState 触发重建
setState(() => _showText = !_showText),
child: Text(_showText ? '删 除' : '添 加'),
),
],
),
),
);
}
}
关键点只有两步
-
条件渲染
dartif (_showText) Text(...)
当
_showText
为true
时,这段Text
进入 Widget 树;为false
时直接"删除"。 -
修改状态 +
setState()
dartsetState(() => _showText = !_showText);
每次点击按钮切换布尔值,Flutter 重新执行
build()
,布局实时更新。
就这么简单:控制一份状态 →
setState
→ 在 UI 层用if
决定渲染与否,即可在运行时随时"添加"或"删除"任意 Widget。
如何创建自定义(控件)Widget?
只需继承 StatelessWidget
并在 build()
中返回组合好的子组件即可。
-
继承
StatelessWidget
/StatefulWidget
-
在
build()
中组合已有控件形成新外观 -
通过构造参数暴露可配置属性,方便复用
1. 自定义控件 NiceCard
dart
import 'package:flutter/material.dart';
/// 自定义 Widget:圆角卡片 + 居中文字
class NiceCard extends StatelessWidget {
// ------ 可配置参数 ------ //
final String text; // 显示的文字
final Color color; // 背景色
final double width; // 宽度
final double height; // 高度
const NiceCard({
super.key,
required this.text,
this.color = Colors.indigo,
this.width = 160,
this.height = 80,
});
@override
Widget build(BuildContext context) {
return Container(
width: width,
height: height,
alignment: Alignment.center,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(12),
boxShadow: const [BoxShadow(blurRadius: 4, color: Colors.black26)],
),
child: Text(
text,
style: const TextStyle(color: Colors.white, fontSize: 18),
),
);
}
}
关键点
步骤 | 说明 |
---|---|
继承 | StatelessWidget (如需内部状态可换 StatefulWidget ) |
参数 | 在构造函数传入可配置项,外部调用时灵活设定 |
组合 | 用现有 Widget(Container + Text )拼装出新的控件 |
2. 在页面中使用
dart
void main() => runApp(const MaterialApp(home: DemoPage()));
class DemoPage extends StatelessWidget {
const DemoPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('自定义 Widget 示例')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
NiceCard(text: '默认卡片'), // 使用默认颜色
SizedBox(height: 20),
NiceCard( // 自定义颜色 & 尺寸
text: '个性卡片',
color: Colors.teal,
width: 200,
height: 100,
),
],
),
),
);
}
}
如何添加/创建一个滚动列表?
Flutter 中创建一个可滚动列表 ------ 只需 ListView.builder
下面用 最少代码 演示如何在 Flutter 中创建一个可滚动列表 ------ 只需 ListView.builder
dart
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: SimpleListPage()));
class SimpleListPage extends StatelessWidget {
const SimpleListPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('滚动列表示例')),
// ① ListView.builder:按需懒加载,适合长列表
body: ListView.builder(
itemCount: 50, // 列表长度
itemBuilder: (context, index) => ListTile( // 每行 UI
leading: const Icon(Icons.album),
title: Text('列表项 #$index'),
subtitle: const Text('这是子标题'),
),
),
);
}
}
代码要点
步骤 | 说明 |
---|---|
① 选择构造函数 | ListView.builder 会按需创建 / 回收 item,性能等同 Android RecyclerView 。 |
itemCount |
指定总项数(不确定可设 null 并用 List.generate )。 |
itemBuilder |
返回单行 Widget,可自定义复杂布局。 |
如果列表项很少,可直接用 静态 children:
dart
ListView(
padding: const EdgeInsets.all(8),
children: const [
ListTile(title: Text('A')),
ListTile(title: Text('B')),
ListTile(title: Text('C')),
],
)
两种写法即可覆盖从几十条到成千上万条数据的滚动需求。
监听 Widget 手势的几种常见方式
级别 | 组件 / API | 适用场景 | 关键回调示例 |
---|---|---|---|
高阶封装 | GestureDetector |
点击、双击、长按、拖动、缩放等常见交互 | onTap onDoubleTap onLongPress onPanUpdate |
InkWell / InkResponse |
需要 Material 水波纹 点击效果 | 同上(内部依旧用 GestureDetector ) |
|
中阶监听 | Listener |
直接拿 Pointer 级别事件;不做手势冲突处理 | onPointerDown onPointerMove |
MouseRegion |
桌面 / Web 悬停、移入移出 | onEnter onHover onExit |
|
深度定制 | RawGestureDetector |
自定义手势识别、参与 Arena 决策 | 手动注册 GestureRecognizer |
辅助控制 | AbsorbPointer / IgnorePointer |
临时禁用或穿透点击 | absorbing / ignoring 布尔值 |
选型口诀:
- 能用
GestureDetector
就别用底层;- 要水波纹 →
InkWell
;- 只取原始坐标 →
Listener
。
示例:Listener
获取原始触点坐标
dart
Listener(
onPointerMove: (e) => print('位置: ${e.position}'),
child: Container(width: 120, height: 120, color: Colors.grey),
)
- 不做任何手势优先级判断,事件会一直往子树传递。
GestureDetector
的使用
GestureDetector
是 Flutter 最常用的 手势封装组件,内部已处理好点击/拖动等手势竞争,直接包一层即可监听。
常用回调 | 触发时机 |
---|---|
onTap |
单击抬起 |
onDoubleTap |
两次点击间隔 < 300 ms |
onLongPress |
默认按住 500 ms |
onPanStart / Update / End |
手指拖动 |
onScaleStart / Update / End |
双指缩放或旋转 |
示例:点击切色 & 长按提示
dart
class SimpleGestureBox extends StatefulWidget {
const SimpleGestureBox({super.key});
@override
State<SimpleGestureBox> createState() => _SimpleGestureBoxState();
}
class _SimpleGestureBoxState extends State<SimpleGestureBox> {
Color _color = Colors.indigo;
@override
Widget build(BuildContext context) {
return GestureDetector(
// 单击:切换背景色
onTap: () => setState(() {
_color = _color == Colors.indigo ? Colors.teal : Colors.indigo;
}),
// 长按:SnackBar 提示
onLongPress: () =>
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('长按触发!')),
),
child: Container(
width: 140,
height: 140,
alignment: Alignment.center,
decoration: BoxDecoration(
color: _color,
borderRadius: BorderRadius.circular(12),
),
child: const Text('点 / 长按', style: TextStyle(color: Colors.white)),
),
);
}
}
- 用法 :把任何 Widget(这里是
Container
)包在GestureDetector
; - 交互 :单击瞬间更换颜色;长按弹出底部提示;其余布局无须管理刷新------
setState()
已触发重建。