Flutter之Widget学习指南

📚 目录

  1. Widget 基础概念
  2. Widget 的类型
  3. 常用 Widget 详解
  4. Widget 生命周期
  5. 最佳实践

Widget 基础概念

什么是 Widget?

Widget 是 Flutter 应用的基础构建块。在 Flutter 中,一切都是 Widget

  • Widget 是配置对象:它们描述了用户界面的一部分应该如何显示
  • Widget 是不可变的(Immutable):一旦创建,其属性就不能改变
  • Widget 是轻量级的:它们只是配置信息,不是实际的渲染对象
  • Widget 树:所有 Widget 组成一个树形结构,描述了整个 UI 的层次关系

Widget 的核心特性

  1. 不可变性(Immutability)

    • Widget 一旦创建就不能修改
    • 要更新 UI,需要创建新的 Widget
    • 这确保了 UI 的一致性和可预测性
  2. 组合性(Composition)

    • Widget 可以嵌套其他 Widget
    • 通过组合简单的 Widget 来构建复杂的 UI
  3. 声明式编程(Declarative)

    • 你描述 UI 应该是什么样子,而不是如何构建它
    • Flutter 框架负责实际的渲染工作

Widget 的类型

1. StatelessWidget(无状态 Widget)

特点:

  • 一旦创建,其属性就不能改变
  • 不持有可变的状态
  • 适用于静态内容或只依赖于传入参数的内容

使用场景:

  • 显示静态文本
  • 展示图片
  • 简单的布局容器
  • 不需要用户交互的 UI 元素

示例:

class MyText extends StatelessWidget {
  final String text;
  
  const MyText({super.key, required this.text});

  @override
  Widget build(BuildContext context) {
    return Text(text);
  }
}

2. StatefulWidget(有状态 Widget)

特点:

  • 可以持有可变的状态
  • 当状态改变时,会调用 setState() 重新构建 UI
  • 由两部分组成:Widget 类和 State 类

使用场景:

  • 需要用户交互的界面
  • 需要根据数据变化更新的 UI
  • 表单输入
  • 动画效果

示例:

class Counter extends StatefulWidget {
  const Counter({super.key});

  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('计数: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: const Text('增加'),
        ),
      ],
    );
  }
}

重要概念:

  • setState():通知 Flutter 状态已改变,需要重新构建 Widget
  • State 对象在 Widget 重建时会被保留
  • State 对象可以持有可变的数据

常用 Widget 详解

应用入口 Widget

MaterialApp(Android 风格应用)

  • 用途:Android 风格应用的根 Widget,提供主题、路由、本地化等功能
  • 详细属性
    • title:应用标题(String),用于任务管理器显示
    • home:应用启动时显示的主页面(Widget)
    • theme:应用主题(ThemeData),定义颜色、字体、组件样式等
    • darkTheme:深色主题(ThemeData)
    • themeMode:主题模式(ThemeMode):systemlightdark
    • routes:命名路由表(Map<String, WidgetBuilder>)
    • initialRoute:初始路由名称(String)
    • onGenerateRoute:路由生成器(RouteFactory)
    • onUnknownRoute:未知路由处理器(RouteFactory)
    • locale:当前语言环境(Locale)
    • supportedLocales:支持的语言环境列表(List<Locale>)
    • localizationsDelegates:本地化代理列表
    • debugShowCheckedModeBanner:是否显示右上角调试横幅(bool,默认 true)
    • color:应用主色(Color),用于系统 UI
    • builder:构建器函数,用于包装整个应用
    • navigatorKey:导航器键(GlobalKey<NavigatorState>)
    • navigatorObservers:导航器观察者列表
    • scaffoldMessengerKey:ScaffoldMessenger 的键
  • 示例
    MaterialApp(
      title: '我的应用',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      darkTheme: ThemeData.dark(),
      themeMode: ThemeMode.system,
      home: const HomePage(),
      routes: {
        '/home': (context) => const HomePage(),
        '/settings': (context) => const SettingsPage(),
      },
      debugShowCheckedModeBanner: false,
    );
    

CupertinoApp(iOS 风格应用)

  • 用途:iOS 风格应用的根 Widget,提供 iOS 风格的组件和主题
  • 详细属性
    • title:应用标题(String)
    • home:应用启动时显示的主页面(Widget)
    • theme:Cupertino 主题(CupertinoThemeData)
    • routes:命名路由表(Map<String, WidgetBuilder>)
    • initialRoute:初始路由名称(String)
    • onGenerateRoute:路由生成器(RouteFactory)
    • onUnknownRoute:未知路由处理器(RouteFactory)
    • locale:当前语言环境(Locale)
    • supportedLocales:支持的语言环境列表(List<Locale>)
    • localizationsDelegates:本地化代理列表
    • debugShowCheckedModeBanner:是否显示调试横幅(bool)
    • color:应用主色(Color)
    • builder:构建器函数
    • navigatorKey:导航器键
    • navigatorObservers:导航器观察者列表
  • 示例
    CupertinoApp(
      title: 'iOS 风格应用',
      theme: const CupertinoThemeData(
        primaryColor: CupertinoColors.systemBlue,
        brightness: Brightness.light,
      ),
      home: const HomePage(),
      debugShowCheckedModeBanner: false,
    );
    
  • MaterialApp vs CupertinoApp
    • MaterialApp:Android Material Design 风格
    • CupertinoApp:iOS Cupertino 风格
    • 若需实现 “Android 用 Material,iOS 用 Cupertino” 的自适应效果:可通过 Platform.isIOS 动态判断平台,选择对应的顶层容器
    • 示例
    import 'dart:io';
    import 'package:flutter/material.dart';
    import 'package:flutter/cupertino.dart';
    
    void main() {
      runApp(
        Platform.isIOS 
            ? CupertinoApp(home: IosHomePage()) // iOS 用 CupertinoApp
            : MaterialApp(home: AndroidHomePage()) // Android 用 MaterialApp
      );
    }
    

Scaffold(页面骨架)

  • 用途:整个页面的基础布局框架,提供 AppBarDrawerFloatingActionButton 等常见布局位置
  • 详细属性
    • appBar:顶部应用栏(PreferredSizeWidget?)
    • body:页面主体内容(Widget?)
    • floatingActionButton:浮动按钮(Widget?)
    • floatingActionButtonLocation:浮动按钮位置(FloatingActionButtonLocation?)
    • floatingActionButtonAnimator:浮动按钮动画器(FloatingActionButtonAnimator?)
    • persistentFooterButtons:持久底部按钮列表(List<Widget>?)
    • drawer:左侧抽屉(Widget?)
    • endDrawer:右侧抽屉(Widget?)
    • bottomNavigationBar:底部导航栏(Widget?)
    • bottomSheet:底部表单(Widget?)
    • backgroundColor:背景色(Color?)
    • resizeToAvoidBottomInset:是否调整大小避免底部插入(bool?)
    • primary:是否为主应用栏(bool?)
    • drawerDragStartBehavior:抽屉拖拽开始行为(DragStartBehavior)
    • extendBody:是否扩展主体(bool)
    • extendBodyBehindAppBar:是否在 AppBar 后扩展主体(bool)
    • drawerScrimColor:抽屉遮罩颜色(Color?)
    • drawerEdgeDragWidth:抽屉边缘拖拽宽度(double?)
    • drawerEnableOpenDragGesture:是否启用抽屉打开手势(bool)
    • endDrawerEnableOpenDragGesture:是否启用右侧抽屉打开手势(bool)
    • restorationId:恢复 ID(String?)
  • 示例
    Scaffold(
      appBar: AppBar(
        title: const Text('Scaffold 示例'),
        actions: [
          IconButton(
            icon: const Icon(Icons.search),
            onPressed: () {},
          ),
        ],
      ),
      body: const Center(child: Text('这里是主体内容')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        child: const Icon(Icons.add),
      ),
      drawer: const Drawer(
        child: Center(child: Text('左侧抽屉菜单')),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
        ],
      ),
    );
    

AppBar(应用栏)

  • 用途:页面顶部的标题栏,通常放标题、操作按钮、Tab 等
  • 详细属性
    • title:主标题(Widget),常用 Text
    • leading:左侧按钮(Widget?),通常是返回按钮或菜单按钮
    • actions:右侧动作按钮列表(List<Widget>?)
    • backgroundColor:背景色(Color?)
    • foregroundColor:前景色(Color?)
    • elevation:阴影高度(double?)
    • shadowColor:阴影颜色(Color?)
    • iconTheme:图标主题(IconThemeData?)
    • actionsIconTheme:动作图标主题(IconThemeData?)
    • textTheme:文本主题(TextTheme?)
    • centerTitle:是否居中标题(bool?)
    • titleSpacing:标题间距(double?)
    • toolbarHeight:工具栏高度(double?)
    • toolbarOpacity:工具栏透明度(double?)
    • bottom:底部 Widget(PreferredSizeWidget?),常用于 TabBar
    • flexibleSpace:灵活空间(Widget?)
    • brightness:亮度(Brightness?)
    • automaticallyImplyLeading:是否自动显示 leading(bool?)
    • primary:是否为主应用栏(bool?)
    • excludeHeaderSemantics:是否排除头部语义(bool?)
    • toolbarTextStyle:工具栏文本样式(TextStyle?)
    • titleTextStyle:标题文本样式(TextStyle?)
    • systemOverlayStyle:系统覆盖层样式(SystemUiOverlayStyle?)
  • 示例
    AppBar(
      title: const Text('Widget 学习'),
      leading: IconButton(
        icon: const Icon(Icons.menu),
        onPressed: () {},
      ),
      actions: [
        IconButton(
          icon: const Icon(Icons.notifications),
          onPressed: () {},
        ),
        IconButton(
          icon: const Icon(Icons.account_circle),
          onPressed: () {},
        ),
      ],
      centerTitle: true,
      backgroundColor: Colors.indigo,
      elevation: 4,
    );
    

布局 Widget

1. Container(容器)

  • 用途:最常用的布局 Widget,可以设置尺寸、内边距、外边距、装饰等
  • 详细属性
    • child:子 Widget(Widget)
    • alignment:子 Widget 对齐方式(AlignmentGeometry)
    • padding:内边距(EdgeInsetsGeometry)
    • margin:外边距(EdgeInsetsGeometry)
    • width:宽度(double)
    • height:高度(double)
    • constraints:布局约束(BoxConstraints)
    • decoration:装饰(BoxDecoration)
      • color:背景色
      • image:背景图片
      • border:边框(Border)
      • borderRadius:圆角(BorderRadius)
      • boxShadow:阴影列表(List<BoxShadow>)
      • gradient:渐变(Gradient)
      • shape:形状(BoxShape):rectanglecircle
    • foregroundDecoration:前景装饰(Decoration)
    • transform:变换矩阵(Matrix4)
    • clipBehavior:裁剪行为(Clip)
  • 示例
    Container(
      width: 200,
      height: 100,
      padding: const EdgeInsets.all(16),
      margin: const EdgeInsets.all(8),
      decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: Colors.black, width: 2),
        boxShadow: [
          BoxShadow(
            color: Colors.grey.withOpacity(0.5),
            spreadRadius: 2,
            blurRadius: 5,
            offset: const Offset(0, 3),
          ),
        ],
      ),
      child: const Text('容器内容'),
    );
    

2. Row(行)

  • 用途:水平排列子 Widget
  • 详细属性
    • children:子 Widget 列表(List<Widget>)
    • mainAxisAlignment:主轴对齐方式(MainAxisAlignment)
      • start:开始对齐
      • end:结束对齐
      • center:居中对齐
      • spaceBetween:两端对齐,中间均匀分布
      • spaceAround:均匀分布,两端有间距
      • spaceEvenly:均匀分布,包括两端
    • crossAxisAlignment:交叉轴对齐方式(CrossAxisAlignment)
      • start:开始对齐
      • end:结束对齐
      • center:居中对齐
      • stretch:拉伸填充
      • baseline:基线对齐
    • mainAxisSize:主轴尺寸(MainAxisSize):minmax
    • textDirection:文本方向(TextDirection):ltrrtl
    • verticalDirection:垂直方向(VerticalDirection):downup
    • textBaseline:文本基线(TextBaseline)
  • 示例
    Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Container(width: 50, height: 50, color: Colors.red),
        Container(width: 50, height: 50, color: Colors.green),
        Container(width: 50, height: 50, color: Colors.blue),
      ],
    );
    

3. Column(列)

  • 用途:垂直排列子 Widget
  • 详细属性:与 Row 相同,但主轴和交叉轴互换
  • 示例
    Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Container(width: 50, height: 50, color: Colors.red),
        Container(width: 50, height: 50, color: Colors.green),
        Container(width: 50, height: 50, color: Colors.blue),
      ],
    );
    

4. Stack(堆叠)

  • 用途:将 Widget 叠加在一起
  • 详细属性
    • children:子 Widget 列表(List<Widget>),后面的在上层
    • alignment:对齐方式(AlignmentGeometry),默认 AlignmentDirectional.topStart
    • fit:子 Widget 的适应方式(StackFit)
      • loose:宽松适应
      • expand:扩展填充
      • passthrough:传递约束
    • clipBehavior:裁剪行为(Clip):nonehardEdgeantiAliasantiAliasWithSaveLayer
    • textDirection:文本方向(TextDirection)
  • 示例
    Stack(
      alignment: Alignment.center,
      children: [
        Container(width: 200, height: 200, color: Colors.blue),
        Container(width: 100, height: 100, color: Colors.red.withOpacity(0.7)),
        const Text('Stack 示例'),
      ],
    );
    

5. Expanded(扩展)

  • 用途:在 Row 或 Column 中占用剩余空间
  • 详细属性
    • child:子 Widget(Widget)
    • flex:占用比例(int),默认为 1
  • 示例
    Row(
      children: [
        Expanded(
          flex: 1,
          child: Container(height: 100, color: Colors.red),
        ),
        Expanded(
          flex: 2,
          child: Container(height: 100, color: Colors.blue),
        ),
      ],
    );
    

6. Flexible(灵活)

  • 用途:类似 Expanded,但不强制填充所有空间
  • 详细属性
    • child:子 Widget(Widget)
    • flex:占用比例(int),默认为 1
    • fit:适应方式(FlexFit):tight(紧密,类似 Expanded)、loose(宽松)
  • 示例
    Row(
      children: [
        Flexible(
          flex: 1,
          fit: FlexFit.loose,
          child: Container(height: 100, color: Colors.green),
        ),
        Flexible(
          flex: 2,
          fit: FlexFit.loose,
          child: Container(height: 100, color: Colors.orange),
        ),
      ],
    );
    

7. SizedBox(固定尺寸盒子)

  • 用途:固定尺寸的容器,也常用于添加间距
  • 详细属性
    • width:宽度(double)
    • height:高度(double)
    • child:子 Widget(Widget)
  • 示例
    SizedBox(
      width: 200,
      height: 100,
      child: const Text('固定尺寸'),
    );
    
    // 用作间距
    const SizedBox(height: 20);
    const SizedBox(width: 10);
    

8. Padding(内边距)

  • 用途:添加内边距
  • 详细属性
    • padding:内边距(EdgeInsetsGeometry)
      • EdgeInsets.all(20):所有方向
      • EdgeInsets.symmetric(horizontal: 20, vertical: 10):对称
      • EdgeInsets.only(left: 10, top: 20, right: 10, bottom: 20):各方向不同
    • child:子 Widget(Widget)
  • 示例
    Padding(
      padding: const EdgeInsets.all(20),
      child: Container(color: Colors.blue, child: const Text('带内边距')),
    );
    

9. Center(居中)

  • 用途:将子 Widget 居中
  • 详细属性
    • child:子 Widget(Widget)
    • widthFactor:宽度因子(double),如果设置,宽度 = 子 Widget 宽度 × widthFactor
    • heightFactor:高度因子(double),如果设置,高度 = 子 Widget 高度 × heightFactor
  • 示例
    Center(
      child: Container(
        width: 100,
        height: 100,
        color: Colors.purple,
      ),
    );
    

10. Wrap(自动换行)

  • 用途:自动换行的布局,类似 Row/Column 但可以换行
  • 详细属性
    • children:子 Widget 列表(List<Widget>)
    • direction:方向(Axis):horizontalvertical
    • alignment:对齐方式(WrapAlignment)
    • spacing:主轴间距(double)
    • runSpacing:交叉轴间距(double)
    • crossAxisAlignment:交叉轴对齐方式(WrapCrossAlignment)
    • textDirection:文本方向(TextDirection)
    • verticalDirection:垂直方向(VerticalDirection)
  • 示例
    Wrap(
      spacing: 8,
      runSpacing: 8,
      children: List.generate(10, (index) {
        return Chip(
          label: Text('标签 $index'),
        );
      }),
    );
    

文本 Widget

Text(文本)

  • 用途:显示文本
  • 详细属性
    • data:文本内容(String)
    • style:文本样式(TextStyle)
      • fontSize:字体大小(double)
      • fontWeight:字体粗细(FontWeight):normalboldw100-w900
      • fontStyle:字体样式(FontStyle):normalitalic
      • color:文字颜色(Color)
      • backgroundColor:背景色(Color)
      • letterSpacing:字符间距(double)
      • wordSpacing:单词间距(double)
      • height:行高(double)
      • decoration:文本装饰(TextDecoration):noneunderlineoverlinelineThrough
      • decorationColor:装饰颜色(Color)
      • decorationStyle:装饰样式(TextDecorationStyle)
      • fontFamily:字体家族(String)
    • textAlign:文本对齐(TextAlign):leftrightcenterjustifystartend
    • textDirection:文本方向(TextDirection)
    • maxLines:最大行数(int)
    • overflow:溢出处理(TextOverflow):clipfadeellipsisvisible
    • textScaleFactor:文本缩放因子(double)
    • semanticsLabel:语义标签(String),用于无障碍
    • softWrap:是否自动换行(bool)
    • textWidthBasis:文本宽度基础(TextWidthBasis)
  • 示例
    Text(
      '这是文本示例',
      style: TextStyle(
        fontSize: 24,
        fontWeight: FontWeight.bold,
        color: Colors.blue,
        decoration: TextDecoration.underline,
      ),
      textAlign: TextAlign.center,
      maxLines: 2,
      overflow: TextOverflow.ellipsis,
    );
    

按钮 Widget

ElevatedButton(凸起按钮)

  • 用途:有阴影的按钮,适合主要操作
  • 详细属性
    • onPressed:点击回调(VoidCallback?),为 null 时按钮禁用
    • onLongPress:长按回调(VoidCallback?)
    • child:子 Widget(Widget),通常是 Text 或 Icon
    • style:按钮样式(ButtonStyle)
    • autofocus:是否自动聚焦(bool)
    • clipBehavior:裁剪行为(Clip)
  • 示例
    ElevatedButton(
      onPressed: () {
        print('按钮被点击');
      },
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(8),
        ),
      ),
      child: const Text('凸起按钮'),
    );
    

TextButton(文本按钮)

  • 用途:扁平按钮,适合次要操作
  • 详细属性:与 ElevatedButton 相同
  • 示例
    TextButton(
      onPressed: () {},
      child: const Text('文本按钮'),
    );
    

OutlinedButton(轮廓按钮)

  • 用途:有边框的按钮
  • 详细属性:与 ElevatedButton 相同
  • 示例
    OutlinedButton(
      onPressed: () {},
      child: const Text('轮廓按钮'),
    );
    

IconButton(图标按钮)

  • 用途:只显示图标的按钮
  • 详细属性
    • icon:图标(Widget),通常是 Icon
    • onPressed:点击回调(VoidCallback?)
    • onLongPress:长按回调(VoidCallback?)
    • iconSize:图标大小(double)
    • color:图标颜色(Color?)
    • disabledColor:禁用时颜色(Color?)
    • tooltip:工具提示(String?)
    • autofocus:是否自动聚焦(bool)
    • focusNode:焦点节点(FocusNode?)
    • constraints:约束(BoxConstraints?)
    • style:按钮样式(ButtonStyle?)
  • 示例
    IconButton(
      icon: const Icon(Icons.favorite),
      onPressed: () {},
      iconSize: 30,
      color: Colors.red,
      tooltip: '收藏',
    );
    

输入 Widget

TextField(文本输入框)

  • 用途:单行文本输入
  • 详细属性
    • controller:文本控制器(TextEditingController?)
    • decoration:输入框装饰(InputDecoration?)
      • labelText:标签文本
      • hintText:提示文本
      • helperText:帮助文本
      • errorText:错误文本
      • prefixIcon:前缀图标
      • suffixIcon:后缀图标
      • border:边框样式
      • filled:是否填充背景
      • fillColor:填充颜色
    • onChanged:文本改变时的回调(ValueChanged<String>?)
    • onSubmitted:提交时的回调(ValueChanged<String>?)
    • keyboardType:键盘类型(TextInputType)
    • textInputAction:输入动作(TextInputAction)
    • obscureText:是否隐藏文本(bool),用于密码输入
    • maxLines:最大行数(int),默认为 1
    • maxLength:最大长度(int?)
    • enabled:是否启用(bool)
    • readOnly:是否只读(bool)
    • autofocus:是否自动聚焦(bool)
    • style:文本样式(TextStyle?)
    • textAlign:文本对齐(TextAlign)
    • textCapitalization:文本大写(TextCapitalization)
  • 示例
    TextField(
      controller: TextEditingController(),
      decoration: const InputDecoration(
        labelText: '用户名',
        hintText: '请输入用户名',
        prefixIcon: Icon(Icons.person),
        border: OutlineInputBorder(),
      ),
      onChanged: (value) {
        print('输入内容: $value');
      },
      keyboardType: TextInputType.text,
    );
    

TextFormField(表单输入框)

  • 用途:带验证的表单输入
  • 详细属性:继承 TextField 的所有属性,额外包括:
    • validator:验证函数(FormFieldValidator<String>?)
    • autovalidateMode:自动验证模式(AutovalidateMode?)
    • onSaved:保存时的回调(FormFieldSetter<String>?)
  • 示例
    TextFormField(
      decoration: const InputDecoration(
        labelText: '邮箱',
        border: OutlineInputBorder(),
      ),
      validator: (value) {
        if (value == null || value.isEmpty) {
          return '请输入邮箱';
        }
        if (!value.contains('@')) {
          return '邮箱格式不正确';
        }
        return null;
      },
      autovalidateMode: AutovalidateMode.onUserInteraction,
    );
    

列表 Widget

ListView(列表视图)

  • 用途:可滚动的列表
  • 详细属性
    • children:子 Widget 列表(List<Widget>),用于 ListView()
    • itemBuilder:列表项构建器(IndexedWidgetBuilder?),用于 ListView.builder()
    • itemCount:列表项数量(int?),用于 ListView.builder()
    • separatorBuilder:分隔符构建器(IndexedWidgetBuilder?),用于 ListView.separated()
    • scrollDirection:滚动方向(Axis):verticalhorizontal
    • reverse:是否反向滚动(bool)
    • controller:滚动控制器(ScrollController?)
    • physics:滚动物理效果(ScrollPhysics?)
    • padding:内边距(EdgeInsetsGeometry?)
    • shrinkWrap:是否收缩包装(bool)
    • cacheExtent:缓存范围(double?)
  • 变体
    • ListView():直接创建列表项,适合少量固定项
    • ListView.builder():懒加载,性能更好,适合大量动态项
    • ListView.separated():带分隔符的列表
  • 示例
    // ListView
    ListView(
      children: [
        ListTile(title: Text('项目 1')),
        ListTile(title: Text('项目 2')),
      ],
    );
    
    // ListView.builder
    ListView.builder(
      itemCount: 100,
      itemBuilder: (context, index) {
        return ListTile(title: Text('项目 ${index + 1}'));
      },
    );
    
    // ListView.separated
    ListView.separated(
      itemCount: 10,
      separatorBuilder: (context, index) => const Divider(),
      itemBuilder: (context, index) {
        return ListTile(title: Text('项目 ${index + 1}'));
      },
    );
    

其他常用 Widget

Card(卡片)

  • 用途:带阴影和圆角的容器
  • 详细属性
    • child:子 Widget(Widget)
    • elevation:阴影高度(double),默认 1.0
    • margin:外边距(EdgeInsetsGeometry?)
    • shape:形状(ShapeBorder?)
    • color:背景色(Color?)
    • shadowColor:阴影颜色(Color?)
    • clipBehavior:裁剪行为(Clip)
  • 示例
    Card(
      elevation: 5,
      margin: const EdgeInsets.all(16),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10),
      ),
      child: const ListTile(
        title: Text('卡片标题'),
        subtitle: Text('卡片内容'),
      ),
    );
    

Icon(图标)

  • 用途:显示 Material Design 图标
  • 详细属性
    • icon:图标数据(IconData)
    • size:图标大小(double?),默认 24.0
    • color:图标颜色(Color?)
    • semanticLabel:语义标签(String?)
    • textDirection:文本方向(TextDirection?)
  • 示例
    Icon(
      Icons.favorite,
      size: 40,
      color: Colors.red,
    );
    

Image(图片)

  • 用途:显示图片(网络、本地、资源)
  • 详细属性
    • image:图片提供者(ImageProvider)
    • width:宽度(double?)
    • height:高度(double?)
    • fit:适应方式(BoxFit)
      • fill:填充
      • contain:包含
      • cover:覆盖
      • fitWidth:适应宽度
      • fitHeight:适应高度
      • none:不缩放
      • scaleDown:缩小
    • alignment:对齐方式(AlignmentGeometry)
    • repeat:重复方式(ImageRepeat)
    • loadingBuilder:加载构建器(ImageLoadingBuilder?)
    • errorBuilder:错误构建器(ImageErrorWidgetBuilder?)
    • frameBuilder:帧构建器(ImageFrameBuilder?)
    • semanticLabel:语义标签(String?)
  • 创建方式
    • Image.network():网络图片
    • Image.asset():资源图片
    • Image.file():本地文件
    • Image.memory():内存图片
  • 示例
    Image.network(
      'https://example.com/image.jpg',
      width: 200,
      height: 200,
      fit: BoxFit.cover,
      loadingBuilder: (context, child, progress) {
        if (progress == null) return child;
        return const CircularProgressIndicator();
      },
      errorBuilder: (context, error, stackTrace) {
        return const Icon(Icons.error);
      },
    );
    

Widget 生命周期

StatelessWidget 生命周期

  1. 创建:Widget 被创建
  2. build():构建 Widget 树
  3. 销毁:Widget 从树中移除

StatefulWidget 生命周期

  1. createState():创建 State 对象
  2. initState():State 对象初始化(只调用一次)
  3. didChangeDependencies():依赖改变时调用
  4. build():构建 Widget 树(可能多次调用)
  5. setState():状态改变,触发重建
  6. didUpdateWidget():Widget 配置更新时调用
  7. deactivate():State 对象从树中移除时调用
  8. dispose():State 对象被永久销毁时调用(清理资源)

重要方法:

  • initState():初始化数据、订阅流等
  • dispose():取消订阅、释放资源等

最佳实践

1. 使用 const 构造函数

// ✅ 好的做法
const Text('Hello');

// ❌ 避免
Text('Hello');

2. 合理使用 StatelessWidget 和 StatefulWidget

  • 如果不需要状态,使用 StatelessWidget
  • 只有在需要可变状态时才使用 StatefulWidget

3. 提取 Widget

  • 将复杂的 Widget 拆分成小的、可复用的 Widget
  • 提高代码可读性和可维护性

4. 使用 Key

  • 在列表中使用 Key 帮助 Flutter 识别 Widget
  • 特别是在动态列表中

5. 避免在 build() 中做耗时操作

  • build() 方法应该只负责构建 UI
  • 耗时操作应该在 initState() 或其他生命周期方法中执行

6. 正确使用 setState()

  • 只在需要更新 UI 时调用 setState()
  • 不要在 build() 方法中调用 setState()

7. 管理资源

  • 在 dispose() 中释放资源(控制器、订阅等)
  • 避免内存泄漏

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容