美文网首页
Flutter的Widget学习(六)

Flutter的Widget学习(六)

作者: 来不及变坏 | 来源:发表于2025-09-02 11:00 被阅读0次

引言

在 Flutter 开发中,基础布局、交互控件和视觉装饰组件是构建用户界面的核心。本文将深入讲解以下 6 个常用组件

  • Center:居中布局组件
  • Checkbox:复选框控件
  • Chip:标签/快捷操作组件
  • CircularProgressIndicator:圆形进度指示器
  • ClipOval:椭圆裁剪组件
  • ClipPath:路径裁剪组件

1. Center:居中布局组件

用途:

Center 是最基础的布局组件之一,用于将其子组件在父容器中水平和垂直居中。

示例代码:

class CenterDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Center")),
      body: Container(
        color: Colors.grey[200],
        child: Center(
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
            child: Center(
              child: Text(
                "居中",
                style: TextStyle(color: Colors.white),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

核心参数:

  • child 要居中的子组件
  • widthFactor 宽度因子(如 2.0 表示宽度为子组件的 2 倍)
  • heightFactor 高度因子(同上)

使用场景:

  • 页面内容整体居中
  • 加载状态提示居中
  • 弹窗内容居中
  • 图标与文本组合居中

2. Checkbox:复选框控件

用途:

Checkbox 用于实现二元选择(选中/未选中),常用于表单、设置项等。

示例代码:

class CheckboxDemo extends StatefulWidget {
  @override
  _CheckboxDemoState createState() => _CheckboxDemoState();
}

class _CheckboxDemoState extends State<CheckboxDemo> {
  bool _isChecked = false;
  List<String> _selectedItems = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Checkbox")),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            // 基础 Checkbox
            Row(
              children: [
                Checkbox(
                  value: _isChecked,
                  onChanged: (bool? value) {
                    setState(() {
                      _isChecked = value!;
                    });
                  },
                  activeColor: Colors.blue, // 选中时的颜色
                  checkColor: Colors.white, // 对勾颜色
                ),
                Text("我同意用户协议"),
              ],
            ),

            SizedBox(height: 20),

            // 列表中的 Checkbox
            Text("选择兴趣:"),
            ...["编程", "设计", "音乐", "阅读"].map((item) {
              return Row(
                children: [
                  Checkbox(
                    value: _selectedItems.contains(item),
                    onChanged: (bool? value) {
                      setState(() {
                        if (value!) {
                          _selectedItems.add(item);
                        } else {
                          _selectedItems.remove(item);
                        }
                      });
                    },
                  ),
                  Text(item),
                ],
              );
            }).toList(),
          ],
        ),
      ),
    );
  }
}

核心参数:

  • value 当前是否选中(true/false/null 三态)
  • onChanged 状态改变回调(传入 null 可实现三态)
  • activeColor 选中时的背景色
  • checkColor 对勾图标的颜色
  • materialTapTargetSize 点击区域大小

使用场景:

  • 表单中的“同意协议”选项
  • 多选列表
  • 设置开关(布尔值)
  • 任务完成状态标记

3. Chip:标签/快捷操作组件

用途:

Chip 是 Material Design 中的标签组件,用于展示简短信息、过滤条件或快捷操作。Flutter 提供多种 Chip 类型:

  • Chip:基本标签
  • InputChip:输入建议
  • ChoiceChip:单选标签组
  • FilterChip:多选过滤标签
  • ActionChip:操作按钮

示例代码:多种 Chip 类型

class ChipDemo extends StatefulWidget {
  @override
  _ChipDemoState createState() => _ChipDemoState();
}

class _ChipDemoState extends State<ChipDemo> {
  bool _chipSelected = false;
  String? _choiceChip;
  Set<String> _filterChips = {};

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Chip")),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text("1. 基础 Chip:"),
              Wrap(
                spacing: 8,
                children: [
                  Chip(
                    label: Text("标签1"),
                    avatar: CircleAvatar(child: Text("1")),
                    onDeleted: () {},
                    deleteIcon: Icon(Icons.close, size: 16),
                  ),
                  Chip(
                    label: Text("禁用"),
                    disabledColor: Colors.grey,
                  ),
                ],
              ),

              SizedBox(height: 20),
              Text("2. ChoiceChip(单选):"),
              Wrap(
                spacing: 8,
                children: ["A", "B", "C"].map((letter) {
                  return ChoiceChip(
                    label: Text(letter),
                    selected: _choiceChip == letter,
                    onSelected: (selected) {
                      setState(() {
                        _choiceChip = selected ? letter : null;
                      });
                    },
                    selectedColor: Colors.blue,
                    labelStyle: TextStyle(
                      color: _choiceChip == letter ? Colors.white : Colors.black,
                    ),
                  );
                }).toList(),
              ),

              SizedBox(height: 20),
              Text("3. FilterChip(多选):"),
              Wrap(
                spacing: 8,
                children: ["React", "Vue", "Flutter"].map((tech) {
                  return FilterChip(
                    label: Text(tech),
                    selected: _filterChips.contains(tech),
                    onSelected: (selected) {
                      setState(() {
                        if (selected) {
                          _filterChips.add(tech);
                        } else {
                          _filterChips.remove(tech);
                        }
                      });
                    },
                  );
                }).toList(),
              ),

              SizedBox(height: 20),
              Text("4. ActionChip:"),
              ActionChip(
                label: Text("点击执行操作"),
                onPressed: () {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text("ActionChip 被点击")),
                  );
                },
                avatar: Icon(Icons.play_arrow),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

使用场景:

  • 搜索关键词标签
  • 用户兴趣选择
  • 筛选条件展示
  • 快捷操作按钮
  • 输入建议(InputChip)

4. CircularProgressIndicator:圆形进度指示器

用途:

CircularProgressIndicator 用于显示任务进度,分为确定进度和不确定进度两种模式。

示例代码:

class CircularProgressIndicatorDemo extends StatefulWidget {
  @override
  _CircularProgressIndicatorDemoState createState() =>
      _CircularProgressIndicatorDemoState();
}

class _CircularProgressIndicatorDemoState
    extends State<CircularProgressIndicatorDemo>
    with SingleTickerProviderStateMixin {
  double _progress = 0.0;
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(seconds: 2),
      vsync: this,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _startProgress() {
    _progress = 0.0;
    _controller.reset();
    _controller.forward();
    Timer.periodic(Duration(milliseconds: 50), (timer) {
      setState(() {
        _progress += 0.01;
        if (_progress >= 1.0) {
          _progress = 1.0;
          timer.cancel();
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("CircularProgressIndicator")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 不确定进度(旋转动画)
            Text("加载中..."),
            SizedBox(height: 10),
            CircularProgressIndicator(
              strokeWidth: 4,
              backgroundColor: Colors.grey[300],
              valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
            ),

            SizedBox(height: 40),

            // 确定进度
            Text("确定进度:${(_progress * 100).toInt()}%"),
            SizedBox(height: 10),
            CircularProgressIndicator(
              value: _progress,
              strokeWidth: 8,
              backgroundColor: Colors.grey[200],
              valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
            ),

            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _startProgress,
              child: Text("开始进度"),
            ),
          ],
        ),
      ),
    );
  }
}

核心参数:

value 进度值(null 为不确定,0.0~1.0 为确定)
strokeWidth 圆环宽度
backgroundColor 背景圆环颜色
valueColor 进度圆环颜色(通常用 AlwaysStoppedAnimation)

使用场景:

  • 网络请求加载状态
  • 文件上传/下载进度
  • 初始化等待
  • 页面刷新指示

5. ClipOval:椭圆裁剪组件

用途:

ClipOval 用于将子组件裁剪为椭圆形或圆形,常用于头像、图标等。

示例代码:

class ClipOvalDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("ClipOval")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 圆形头像
            ClipOval(
              child: Image.network(
                'https://source.unsplash.com/random/200x200?face',
                width: 100,
                height: 100,
                fit: BoxFit.cover,
              ),
            ),

            SizedBox(height: 30),

            // 椭圆图片
            ClipOval(
              child: Container(
                width: 150,
                height: 100,
                color: Colors.blue,
                alignment: Alignment.center,
                child: Text(
                  "椭圆",
                  style: TextStyle(color: Colors.white, fontSize: 20),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

使用场景:

  • 用户头像(圆形)
  • 图标圆形背景
  • 椭圆按钮
  • 装饰性裁剪

6. ClipPath:路径裁剪组件

用途:

ClipPath 允许你使用自定义的 Path 来裁剪子组件,实现任意形状的裁剪效果。

示例代码:三角形裁剪

class TriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.moveTo(size.width / 2, 0); // 顶部中点
    path.lineTo(size.width, size.height); // 右下角
    path.lineTo(0, size.height); // 左下角
    path.close(); // 闭合路径
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}

class ClipPathDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("ClipPath")),
      body: Center(
        child: ClipPath(
          clipper: TriangleClipper(),
          child: Container(
            width: 200,
            height: 200,
            color: Colors.red,
            alignment: Alignment.center,
            child: Text(
              "三角形",
              style: TextStyle(color: Colors.white, fontSize: 20),
            ),
          ),
        ),
      ),
    );
  }
}

示例:波浪形裁剪

class WaveClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(0, size.height - 20);
    path.quadraticBezierTo(
      size.width / 2,
      size.height,
      size.width,
      size.height - 20,
    );
    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}

核心参数:

clipper 自定义 CustomClipper<Path>
child 被裁剪的子组件
clipBehavior 裁剪行为(hardEdge、antiAlias 等)

使用场景:

  • 自定义形状头像/按钮
  • 波浪形背景
  • 切角卡片
  • 装饰性 UI 元素

最佳实践建议

  • 使用 Center 快速实现居中布局。
  • 使用 Checkbox 构建表单和设置项。
  • 使用 Chip 管理标签、筛选和快捷操作。
  • 使用 CircularProgressIndicator 提供加载反馈。
  • 使用 ClipOval 快速实现圆形头像。
  • 使用 ClipPath 实现自定义形状,提升 UI 美感。

相关文章

网友评论

      本文标题:Flutter的Widget学习(六)

      本文链接:https://www.haomeiwen.com/subject/ftlbajtx.html