Android开发者如何快速上手Flutter开发

Android 主要概念与 Flutter 对应关系

主要概念 在 Android 中 在 Flutter 中的对应
页面 Activity / Fragment Widget(通常是 StatefulWidget
视图 View WidgetStatelessWidgetStatefulWidget
页面跳转 Intent Navigator / Route
网络库 OkHttpRetrofit httpdio
数据存储 SharedPreferencesSQLite shared_preferencessqflitehive

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 绘制
  • 响应式更新

    • Flutter 的 Widget 是 不可变 对象,状态变更触发重新构建;与 Android View 的"属性改变即生效"有所不同。
操作 Android Flutter
启动新页 startActivity(Intent) Navigator.push(context, route)
返回上一页 finish()/系统返回键 Navigator.pop(context)
携带参数 Intent.putExtra() 构造 Route 时传参或使用 settings

路由管理库 :Flutter 可使用 go_routerauto_route 获得更声明式的导航体验,类似 Android Jetpack Navigation。

4. 网络请求(OkHttp ↔ http / dio)

  • 简单场景http 包封装了 get/post,相当于最轻量版 OkHttp。
  • 复杂需求dio 支持拦截器、队列调度、全局配置,与 Android 的 OkHttp + Retrofit 组合功能接近。
  • 序列化 :Flutter 常配合 json_serializablefreezed;Android 常用 Gson/Moshi、Kotlinx.serialization。

5. 数据存储(SharedPreferences / SQLite ↔ shared_preferences / sqflite)

数据规模 Android Flutter
键值对 SharedPreferences shared_preferences
关系型 SQLite(Room ORM) sqflitedrift ORM
轻量非关系型 --- hive(纯 Dart 无平台通道,性能优)

Flutter 端若需与原生共享数据,可通过平台通道调用 Android SharedPreferences 或 iOS NSUserDefaults


小结

  • Flutter 把所有 UI 概念统一为 Widget,比 Android 视图层级更一致;
  • 生命周期、导航与状态管理是学习迁移的主要难点;
  • 原生常用库(网络、存储)在 Flutter 中都有成熟替代品,并通常以社区 pub 包的形式提供。
    掌握上述映射后,Android 开发者可更快转向 Flutter 并解决常见业务需求。

相关布局对应关系

主要概念 在 Android 中 在 Flutter 中的对应
布局文件 XML 直接用 Dart 代码声明 Widget
线性布局 LinearLayout RowColumn
相对布局 RelativeLayout 组合 ColumnRowStack(必要时配合 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 mainAxisAlignmentcrossAxisAlignment

实践 :绝大多数线性嵌套场景,可通过多层 RowColumnFlex 实现,灵活使用 Expanded 处理权重占比。

3. 相对布局:RelativeLayout ↔ Stack + 组合

  • RelativeLayout 用于"谁在谁旁边/下方" 相对定位

  • Flutter 常用:

    • Stack 负责层叠
    • Positioned/Align 确定相对父级的位置;
    • 或在多层 Row/Column 中穿插 SpacerExpanded 达到同类效果。
  • 新手技巧 :先用 Column+Row 拼到最近似,再局部用 Stack 叠加角标/悬浮按钮。

4. 文本与输入

组件 Android Flutter 补充
文本 TextView Text 通过 styleTextStyle 设置字体、颜色、行距。
输入框 EditText TextField / TextFormField 表单验证时优先用 TextFormField,可配合 FormGlobalKey

5. 约束与权重替代方案

  • Android ConstraintLayout 在 Flutter 中可用 第三方 flutter_constraintlayout,但官方更推荐 declarative 布局思想,通过组合 Widgets 达到约束效果。
  • 布局权重用 Expanded / Flexible;尺寸适配可用 FractionallySizedBoxLayoutBuilder

小结

  • Flutter 把布局拆成更细粒度 Widgets ,大量场景下只需灵活堆叠 RowColumnStack 即可覆盖 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 取代。
  • 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_animationsAnimatedListSliverAnimatedList
差分刷新 DiffUtil 借助状态管理(setState/Provider)+ AnimatedSwitcher / ListView.builder 自动对比

高级 Sliver

  • CustomScrollView + SliverList / SliverGrid / SliverAppBar 可实现折叠头、Sticky Header、吸顶 Tab 等复杂滚动效果,功能与 Android CoordinatorLayout + AppBarLayout + RecyclerView 类似。

5. 常见开发迁移要点

  1. 布局思维转变:告别 XML + Adapter,拥抱声明式 UI 和按需构建。
  2. 性能优化 :Flutter 已默认做了视图缓存和滑动合成,只需关注 item 数量及图片加载(可配合 cached_network_image)。
  3. 嵌套列表NestedScrollView + SliverList 解决滚动冲突,等价于 Android 的 NestedScrollView+RecyclerView
  4. 状态管理 :在 Flutter 中列表刷新主要依赖 setStateProviderRiverpod 等状态框架,而非 Adapter 通知。

小结

  • ScrollView / ListView / RecyclerView 在 Flutter 中统一归于 ScrollableViewportSliver 渲染体系,开发者通过 不同构造函数 (childrenbuilder) 或 不同 Widget (ListViewGridViewCustomScrollView) 来选择最合适实现。
  • 对 Android 开发者而言,理解 懒加载(builder)Sliver声明式刷新 是迁移滚动列表的关键。

快速收手布局开发

如何更新(布局)widgets?

Flutter 中最常见的布局刷新方式------StatefulWidget + setState()

1️⃣ 关键思路

  1. 把会变化的数据(这里是颜色)放到 State 中。
  2. 在手势或逻辑回调里修改数据,一定包在 setState() 内。
  3. 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 ? '删 除' : '添 加'),
            ),
          ],
        ),
      ),
    );
  }
}

关键点只有两步

  1. 条件渲染

    dart 复制代码
    if (_showText) Text(...)

    _showTexttrue 时,这段 Text 进入 Widget 树;为 false 时直接"删除"。

  2. 修改状态 + setState()

    dart 复制代码
    setState(() => _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() 已触发重建。
相关推荐
于冬恋4 分钟前
Web后端开发(请求、响应)
前端
red润10 分钟前
封装hook,复刻掘金社区,暗黑白天主题切换功能
前端·javascript·vue.js
Fly-ping11 分钟前
【前端】vue3性能优化方案
前端·性能优化
curdcv_po13 分钟前
前端开发必要会的,在线JS混淆加密
前端
天生我材必有用_吴用15 分钟前
深入理解JavaScript设计模式之单例模式
前端
LuckySusu15 分钟前
【HTML篇】DOCTYPE 声明:掌握浏览器渲染模式的关键
前端·html
Darling哒16 分钟前
HTML块拖拽交换
前端
码农之王17 分钟前
(一)TypeScript概述和环境搭建
前端·后端·typescript
葬送的代码人生28 分钟前
React组件化哲学:如何优雅地"变秃也变强"
前端·javascript·react.js
用户527096487449029 分钟前
🚀 前端项目代码质量配置Prettier + Commitlint + Husky + Lint-staged
前端