Flutter笔记

Flutter笔记

_

1. 核心基石:Widget、State 与 BuildContext

Flutter 的核心设计理念是 “一切皆为 Widget” 。理解以下三个概念是入门的关键。

1.1 Widget:UI 的“蓝图”

Widget 是不可变的(immutable),用于描述 UI 的配置信息。它分为两大类:

  • StatelessWidget (无状态):静态的,创建后 UI 不再变化(如:文本、图标)。

  • StatefulWidget (有状态):动态的,持有 State 对象,用于存储可变数据并驱动 UI 更新(如:复选框、输入框)。

1.2 State:让 UI“动”起来

当 Widget 需要根据数据变化而重绘时,就需要使用 State。通过调用 setState() 通知框架数据已改变,触发 build 方法重绘。

class _CounterState extends State<Counter> {
  int _count = 0; // 状态数据

  void _increment() {
    setState(() {
      _count++; // 修改数据,触发 UI 重建
    });
  }
  // ... build 方法中展示 _count
}

1.3 BuildContext:Widget 树中的“定位器”

BuildContext 是每个 Widget 在树中的位置句柄,用于查找父级 Widget 或获取主题、路由等信息。

// 获取屏幕宽度
double width = MediaQuery.of(context).size.width;
// 获取主题色
Color primary = Theme.of(context).primaryColor;
// 页面跳转
Navigator.of(context).push(...);

2. 布局组件:搭建 UI 的“脚手架”

Flutter 的布局主要依靠单子组件和多子组件配合。核心规则:约束往下传递,尺寸向上传递,父级决定位置

2.1 线性布局:Row 与 Column

用于将子组件沿水平或垂直方向排列。

Row / Column 共有属性

属性

类型

说明

示例值

children

List<Widget>

子组件列表

[Text('A'), Icon(Icons.star)]

mainAxisAlignment

MainAxisAlignment

主轴对齐方式(Row主轴上水平,Column主轴上垂直)

MainAxisAlignment.center

crossAxisAlignment

CrossAxisAlignment

交叉轴对齐方式(Row交叉轴垂直,Column交叉轴水平)

CrossAxisAlignment.start

mainAxisSize

MainAxisSize

主轴占用的空间大小,默认为 max

MainAxisSize.min

verticalDirection

VerticalDirection

子组件垂直排列顺序(仅影响Column)

VerticalDirection.updown

textDirection

TextDirection

水平排列顺序(仅影响Row)

TextDirection.rtl(从右向左)

示例:

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,  // 均匀分布
  crossAxisAlignment: CrossAxisAlignment.center,    // 垂直居中
  children: [Icon(Icons.home), Text('首页')],
)

2.2 弹性布局:Flex 与 Expanded

Expanded 用于填充父级剩余空间,是构建响应式布局的关键。

Expanded 属性

属性

类型

说明

默认值

flex

int

权重,用于分配父级剩余空间的比例

1

child

Widget

必须的子组件

注意: Expanded 只能作为 RowColumnFlex 的直接子组件。

Row(
  children: [
    Icon(Icons.star),
    Expanded(child: Text("这是一段很长的文本,它会占据剩余的所有空间")),
    Icon(Icons.arrow_forward),
  ],
)

2.3 层叠布局:Stack 与 Positioned

类似于 Android 的 FrameLayout 或 CSS 的 absolute 定位。

Stack 属性

属性

类型

说明

默认值

children

List<Widget>

子组件列表(后面的覆盖前面的)

[]

alignment

AlignmentGeometry

未定位子组件的对齐方式

AlignmentDirectional.topStart

fit

StackFit

控制未定位子组件如何填充Stack

StackFit.loose

clipBehavior

Clip

是否裁剪超出边界的子组件

Clip.hardEdge

Positioned 属性

属性

类型

说明

left / top / right / bottom

double

相对于Stack边界的偏移量(至少指定一个)

width / height

double

强制子组件的宽高

child

Widget

必须的子组件

示例:

Stack(
  alignment: Alignment.center,
  children: [
    Container(width: 200, height: 200, color: Colors.grey),
    Positioned(bottom: 10, right: 10, child: Text('右下角')),
  ],
)

2.4 万能容器:Container

一个组合了绘制、定位、大小调整的便利组件。常用作设置背景、边距、宽高。

Container 属性

属性

类型

说明

默认值

width / height

double

固定宽高

null(根据子组件和约束决定)

constraints

BoxConstraints

约束子组件的最大/最小宽高

null

padding / margin

EdgeInsetsGeometry

内边距 / 外边距

EdgeInsets.zero

color

Color

背景色(与decoration互斥)

null

decoration

Decoration

背景装饰(渐变、边框、圆角等),不能与color同时使用

null

foregroundDecoration

Decoration

前景装饰(覆盖在子组件上方)

null

alignment

AlignmentGeometry

子组件的对齐方式

null

transform

Matrix4

变换矩阵(旋转、缩放等)

null

clipBehavior

Clip

裁剪行为

Clip.none

Decoration 常用子类: BoxDecoration

BoxDecoration(
  color: Colors.blue,
  borderRadius: BorderRadius.circular(8),
  boxShadow: [BoxShadow(blurRadius: 5)],
  gradient: LinearGradient(colors: [Colors.red, Colors.blue]),
)

示例:

Container(
  width: 100,
  height: 100,
  margin: EdgeInsets.all(10),   // 外边距
  padding: EdgeInsets.all(8),   // 内边距
  decoration: BoxDecoration(    // 装饰(背景、边框、圆角)
    color: Colors.blue,
    borderRadius: BorderRadius.circular(8),
    boxShadow: [BoxShadow(blurRadius: 5)],
  ),
  child: Text("Hello"),
)

3. 基础 UI 组件

3.1 Text:文本显示

Text 属性

属性

类型

说明

默认值

data

String

显示的文本

style

TextStyle

文字样式(字体、大小、颜色等)

null(使用主题默认)

textAlign

TextAlign

文本水平对齐

TextAlign.start

textDirection

TextDirection

文本方向(ltr/rtl)

根据locale

softWrap

bool

是否自动换行

true

overflow

TextOverflow

溢出处理(省略号、截断等)

TextOverflow.clip

maxLines

int

最大行数

null(不限)

strutStyle

StrutStyle

文本基线结构(用于精确控制行高)

null

textHeightBehavior

TextHeightBehavior

控制多行文本的高度行为

null

TextStyle 常用属性:

TextStyle(
  fontSize: 16,
  fontWeight: FontWeight.bold,
  color: Colors.red,
  fontFamily: 'Roboto',
  letterSpacing: 1.2,
  height: 1.5,  // 行高倍数
)

示例:

Text(
  'Hello Flutter',
  style: TextStyle(
    fontSize: 24,
    fontWeight: FontWeight.bold,
    color: Colors.deepPurple,
  ),
  textAlign: TextAlign.center,
)

3.2 Image:图片加载

构造方法(静态工厂)

构造器

说明

Image.asset

加载本地资源图片(需在pubspec.yaml中声明)

Image.network

加载网络图片

Image.file

加载本地文件

Image.memory

从内存字节数据加载

Image

直接使用ImageProvider(最底层)

通用属性

属性

类型

说明

默认值

width / height

double

显示宽高(若不指定则按原始尺寸)

null

fit

BoxFit

缩放模式(covercontainfill等)

BoxFit.cover

alignment

AlignmentGeometry

图片在控件内的对齐方式

Alignment.center

repeat

ImageRepeat

重复模式(平铺)

ImageRepeat.noRepeat

color

Color

混合颜色(需配合colorBlendMode使用)

null

colorBlendMode

BlendMode

颜色混合模式

BlendMode.srcIn

filterQuality

FilterQuality

图片缩放质量

FilterQuality.low

errorBuilder

Widget Function(...)

加载失败时构建的Widget

null

frameBuilder

Widget Function(...)

逐帧加载时构建的Widget

null

示例:

// 网络图片
Image.network('https://example.com/pic.png', fit: BoxFit.cover)
// 本地 Assets(需在 pubspec.yaml 声明)
Image.asset('assets/images/logo.png')

3.3 按钮(新版)重要更新

Flutter 3.x 已废弃 FlatButtonRaisedButton,统一使用新按钮。使用 styleFrom 快速定制。

  • TextButton:文字按钮(替代 FlatButton)

  • ElevatedButton:带阴影凸起按钮(替代 RaisedButton)

  • OutlinedButton:边框按钮(替代 OutlineButton)

共有属性

属性

类型

说明

onPressed

VoidCallback?

点击回调,若为null则按钮禁用

onLongPress

VoidCallback?

长按回调

child

Widget

按钮内容(通常是TextIcon

style

ButtonStyle?

按钮样式(推荐使用styleFrom构造)

使用 styleFrom 快速定制

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    foregroundColor: Colors.white,           // 文字/图标颜色
    backgroundColor: Colors.green,           // 背景色
    disabledForegroundColor: Colors.grey,    // 禁用时文字颜色
    disabledBackgroundColor: Colors.lightGrey,
    elevation: 5,                            // 阴影高度
    shadowColor: Colors.black54,             // 阴影颜色
    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
    padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
    minimumSize: Size(120, 48),              // 最小尺寸
    tapTargetSize: MaterialTapTargetSize.shrinkWrap,  // 点击区域大小
  ),
  child: Text('按钮'),
)

各按钮的默认差异

按钮

默认背景

默认阴影

TextButton

透明

ElevatedButton

主题色(或指定颜色)

有阴影

OutlinedButton

透明 + 边框

3.4 TextField:输入框

TextField 属性

属性

类型

说明

默认值

controller

TextEditingController

控制文本内容,必须保留(否则无法获取输入)

null

decoration

InputDecoration

装饰(标签、提示、边框、图标等)

null

keyboardType

TextInputType

键盘类型(数字、邮箱、电话等)

TextInputType.text

obscureText

bool

是否隐藏文本(密码模式)

false

maxLines / minLines

int

最大/最小行数

1

maxLength

int

最大字符数

null(不限)

onChanged

ValueChanged<String>

文本改变时的回调

null

onSubmitted

ValueChanged<String>

提交(回车)时的回调

null

enabled

bool

是否可用

true

autofocus

bool

是否自动获取焦点

false

focusNode

FocusNode

焦点管理

null

InputDecoration 常用属性:

InputDecoration(
  labelText: '用户名',
  hintText: '请输入用户名',
  prefixIcon: Icon(Icons.person),
  suffixIcon: Icon(Icons.clear),
  border: OutlineInputBorder(),
  errorText: _hasError ? '用户名不能为空' : null,
)

示例:

TextField(
  decoration: InputDecoration(
    labelText: '用户名',
    hintText: '请输入用户名',
    prefixIcon: Icon(Icons.person),
    border: OutlineInputBorder(),
  ),
  onChanged: (value) => print(value),
)

4. 交互与手势

Flutter 提供了 GestureDetector 来监听几乎所有手势,也可以直接使用带交互的组件。

GestureDetector 属性

属性

类型

说明

onTap

GestureTapCallback

单击

onDoubleTap

GestureTapCallback

双击

onLongPress

GestureLongPressCallback

长按

onTapDown / onTapUp

GestureTapDownCallback / GestureTapUpCallback

按下 / 抬起

onHorizontalDragStart / onVerticalDragStart

GestureDragStartCallback

横向 / 纵向拖拽开始

onScaleStart / onScaleUpdate

GestureScaleStartCallback / GestureScaleUpdateCallback

缩放开始 / 进行中

child

Widget

手势作用的组件

注意: GestureDetector 可嵌套,事件会按需向上冒泡。若要阻止冒泡,使用 IgnorePointer

GestureDetector(
  onTap: () => print('点击了'),
  onDoubleTap: () => print('双击了'),
  onLongPress: () => print('长按了'),
  child: Container(
    color: Colors.amber,
    width: 100,
    height: 100,
    child: Center(child: Text('点我')),
  ),
)

5. 滚动组件:列表与网格

5.1 ListView:核心列表

ListView 的四种构造方式

构造器

适用场景

ListView()

少量固定子组件

ListView.builder

大量或动态子组件(推荐),按需构建

ListView.separated

带分割线的列表

ListView.custom

完全自定义子组件构建(高级)

常用属性(以 ListView.builder 为例)

属性

类型

说明

默认值

itemCount

int

列表项总数(若不提供则无限)

null

itemBuilder

IndexedWidgetBuilder

根据索引构建子组件

scrollDirection

Axis

滚动方向

Axis.vertical

reverse

bool

是否反向滚动

false

controller

ScrollController

滚动控制器(用于监听滚动位置)

null

physics

ScrollPhysics

滚动物理效果(如弹性、边界)

BouncingScrollPhysicsClampingScrollPhysics(平台相关)

shrinkWrap

bool

是否仅包裹内容高度(慎用,会影响性能)

false

padding

EdgeInsetsGeometry

内边距

EdgeInsets.zero

示例:

ListView.builder(
  itemCount: 100,
  itemBuilder: (context, index) {
    return ListTile(
      leading: Icon(Icons.label),
      title: Text('Item $index'),
    );
  },
)

5.2 新特性:CarouselView(轮播图)

Flutter 3.24 新增的 Material 风格轮播组件。

CarouselView 属性

属性

类型

说明

默认值

children

List<Widget>

轮播项

[]

itemExtent

double?

固定每个子组件的主轴尺寸

null(根据子组件自适应)

scrollDirection

Axis

滚动方向

Axis.horizontal

controller

CarouselController?

轮播控制器(控制翻页)

null

onIndexChanged

ValueChanged<int>

当前页改变回调

null

clipBehavior

Clip

裁剪行为

Clip.hardEdge

示例:

CarouselView(
  itemExtent: 300,
  children: [
    Container(color: Colors.red, child: Center(child: Text('1'))),
    Container(color: Colors.green, child: Center(child: Text('2'))),
    Container(color: Colors.blue, child: Center(child: Text('3'))),
  ],
)

5.3 Sliver:自定义滚动效果

Sliver 组件允许你创建自定义的滚动效果,如可伸缩的头部。Flutter 3.24 新增了 SliverFloatingHeaderPinnedHeaderSliver 等。


6. 主题与样式

6.1 Material 3 (M3)

Flutter 3.x 默认支持 Material 3,通过 useMaterial3: true 启用。

MaterialApp 中的主题配置

属性

类型

说明

推荐值

useMaterial3

bool

是否启用 Material 3

true(新项目强烈推荐)

colorScheme

ColorScheme

颜色方案(M3 的核心)

ColorScheme.fromSeed(seedColor: ...)

textTheme

TextTheme

全局文字样式

默认提供 14 种样式

primaryColor

Color

主要颜色(M2 兼容)

可与 colorScheme 配合

appBarTheme

AppBarTheme

AppBar 的全局样式

AppBarTheme()

cardTheme

CardTheme

注意:Flutter 3.24 中为 CardThemeData

CardThemeData()

6.2 组件主题(新版写法)

Flutter 3.24 后,许多组件主题改为使用 *ThemeData 类(如 CardThemeDataElevatedButtonThemeData),不再直接使用旧版 CardTheme 等。

ThemeData(
  useMaterial3: true,
  colorScheme: ColorScheme.fromSeed(seedColor: Colors.purple),
  // 全局按钮样式
  elevatedButtonTheme: ElevatedButtonThemeData(
    style: ElevatedButton.styleFrom(
      minimumSize: Size(120, 48),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
    ),
  ),
  // 全局卡片样式
  cardTheme: CardThemeData(
    elevation: 4,
    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
  ),
  // 全局文本样式
  textTheme: TextTheme(
    displayLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
    bodyMedium: TextStyle(fontSize: 14),
  ),
)

7. 状态管理(进阶必学)

对于复杂应用,仅用 setState 会导致代码难以维护。推荐使用 Riverpod(目前最流行的方案)。

7.1 Riverpod 常用提供器

提供器类型

作用

使用场景

StateProvider<T>

提供一个可变状态

简单的状态(计数器、开关)

FutureProvider<T>

提供异步数据

网络请求、数据库读取

StreamProvider<T>

提供流式数据

WebSocket、实时数据

Provider<T>

提供不可变对象或依赖注入

单例服务、配置

StateNotifierProvider

配合 StateNotifier 管理复杂状态

复杂业务逻辑

7.2 基本使用示例

// 1. 创建 Provider
final counterProvider = StateProvider<int>((ref) => 0);

// 2. 监听并修改
class HomePage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Scaffold(
      body: Center(child: Text('$count')),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(counterProvider.notifier).state++,
      ),
    );
  }
}

ConsumerWidget 的 build 方法参数:

  • WidgetRef ref:用于读取提供器(ref.watch)或获取 notifier(ref.read)。


8. 实战:计数器应用(综合演练)

结合所学知识,我们不仅能做简单的加减法,还能加入“重置”和“限制负数”的逻辑。

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: 'Flutter Demo',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
      ),
      home: const MyHomePage(title: 'Flutter 进阶计数器'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  void _decrementCounter() {
    setState(() {
      if (_counter > 0) _counter--;
    });
  }

  void _resetCounter() {
    setState(() {
      _counter = 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('点击按钮改变数值:', style: TextStyle(fontSize: 18)),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.displayMedium?.copyWith(
                    fontWeight: FontWeight.bold,
                    color: Theme.of(context).colorScheme.primary,
                  ),
            ),
            const SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(onPressed: _decrementCounter, child: const Text('-')),
                const SizedBox(width: 20),
                ElevatedButton(onPressed: _resetCounter, child: const Text('重置')),
                const SizedBox(width: 20),
                ElevatedButton(onPressed: _incrementCounter, child: const Text('+')),
              ],
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: '增加',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Dart 笔记 2026-03-24

评论区