在这里插入图片描述

Button组件基础

一、Button组件概述

Flutter提供了多种按钮组件,满足不同场景的需求。按钮是用户与应用交互的核心元素,合理的按钮设计能够提升用户体验和应用的整体质量。Flutter的按钮组件经过精心设计,每个都有其特定的使用场景和视觉特点。ElevatedButton具有凸起效果和阴影,用于主要操作和重要功能,重要程度高;TextButton是扁平的、无背景的按钮,用于次要操作和辅助功能,重要程度中等;OutlinedButton有轮廓但没有背景,用于中等重要性操作,重要程度中高;IconButton只包含图标,用于工具栏和列表操作,重要程度中等;FloatingActionButton是圆形悬浮按钮,用于主要入口和快速操作,重要程度最高。

最高优先级

主要操作

中等操作

次要操作

选择按钮类型

操作重要性

FAB

ElevatedButton

OutlinedButton

TextButton

是否需要文字

带文字

仅图标

是否需要图标

带图标

仅文字

二、ElevatedButton详解

ElevatedButton(凸起按钮)是Material Design中最常用的按钮类型,具有凸起效果、带有阴影和背景色,用于强调重要性;不同状态有不同阴影,提供深度感;标准圆角(20dp),具有现代感;点击时有波纹动画,反馈交互。ElevatedButton的特点使其在视觉上非常突出,能够吸引用户的注意力,因此最适合用于应用中最重要的操作,如表单提交、页面跳转、确认操作、主要CTA等。

ElevatedButton的常用属性包括onPressed、onLongPress、child、style和autofocus。onPressed是点击回调,设置为null表示按钮禁用;onLongPress是长按回调,用于触发特殊操作;child是按钮内容,通常是Text或Row等Widget;style是按钮样式,通过ButtonStyle自定义;autofocus控制是否自动聚焦。理解这些属性的用法对于创建符合需求的按钮非常重要。

// ElevatedButton基础示例
class ElevatedButtonExample extends StatelessWidget {
  const ElevatedButtonExample({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('ElevatedButton')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // 普通按钮
            ElevatedButton(
              onPressed: () {
                // 处理点击事件
              },
              child: const Text('普通按钮'),
            ),
            const SizedBox(height: 16),

            // 带图标的按钮
            ElevatedButton.icon(
              icon: const Icon(Icons.add),
              label: const Text('添加'),
              onPressed: () {
                // 处理点击事件
              },
            ),
            const SizedBox(height: 16),

            // 禁用按钮
            ElevatedButton(
              onPressed: null,
              child: const Text('禁用按钮'),
            ),
            const SizedBox(height: 16),

            // 带样式的按钮
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.blue,
                foregroundColor: Colors.white,
                elevation: 4,
                minimumSize: const Size(200, 48),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(24),
                ),
              ),
              onPressed: () {},
              child: const Text('自定义样式'),
            ),
          ],
        ),
      ),
    );
  }
}

三、TextButton详解

TextButton(文本按钮)是最轻量的按钮类型,扁平无背景,轻量化设计,适用于辅助操作;仅包含文字,简洁明了;有波纹反馈,提供点击反馈;通常放在次要位置,不抢焦点,与主按钮配合使用。TextButton适用于对话框辅助、表单辅助、导航辅助和次要操作等场景。

// TextButton示例
class TextButtonExample extends StatelessWidget {
  const TextButtonExample({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('TextButton')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // 普通文本按钮
            TextButton(
              onPressed: () {
                // 处理点击事件
              },
              child: const Text('取消'),
            ),
            const SizedBox(height: 16),

            // 带图标的文本按钮
            TextButton.icon(
              icon: const Icon(Icons.info),
              label: const Text('了解更多'),
              onPressed: () {
                // 处理点击事件
              },
            ),
            const SizedBox(height: 16),

            // 禁用文本按钮
            TextButton(
              onPressed: null,
              child: const Text('禁用'),
            ),
            const SizedBox(height: 16),

            // 带样式的文本按钮
            TextButton(
              style: TextButton.styleFrom(
                foregroundColor: Colors.blue,
                textStyle: const TextStyle(fontSize: 16),
              ),
              onPressed: () {},
              child: const Text('自定义样式'),
            ),
          ],
        ),
      ),
    );
  }
}

四、OutlinedButton详解

OutlinedButton(轮廓按钮)介于ElevatedButton和TextButton之间,有边框,视觉突出,重要性中等;无背景,轻量级;圆角设计,现代感;可定制颜色,灵活性高。OutlinedButton适用于需要强调但不是主要操作的场景,如次要操作、中等重要性操作等。

// OutlinedButton示例
class OutlinedButtonExample extends StatelessWidget {
  const OutlinedButtonExample({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('OutlinedButton')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // 普通轮廓按钮
            OutlinedButton(
              onPressed: () {
                // 处理点击事件
              },
              child: const Text('次要操作'),
            ),
            const SizedBox(height: 16),

            // 带图标的轮廓按钮
            OutlinedButton.icon(
              icon: const Icon(Icons.border_color),
              label: const Text('编辑'),
              onPressed: () {
                // 处理点击事件
              },
            ),
            const SizedBox(height: 16),

            // 禁用轮廓按钮
            OutlinedButton(
              onPressed: null,
              child: const Text('禁用'),
            ),
            const SizedBox(height: 16),

            // 带样式的轮廓按钮
            OutlinedButton(
              style: OutlinedButton.styleFrom(
                foregroundColor: Colors.blue,
                side: const BorderSide(color: Colors.blue, width: 2),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
              ),
              onPressed: () {},
              child: const Text('自定义样式'),
            ),
          ],
        ),
      ),
    );
  }
}

五、按钮交互状态

按钮有多种交互状态,包括空闲、悬停、按下和禁用。空闲状态下按钮正常显示,悬停时按钮颜色变深以提示可交互,按下时阴影减少且背景变深以提供反馈,禁用时按钮变为灰色且透明度降低。这些状态变化通过动画过渡,提供流畅的用户体验。

状态 ElevatedButton OutlinedButton TextButton
空闲 正常背景+阴影 边框+文字 文字
悬停 背景变深 边框变深 文字变深
按下 阴影减少+背景变深 边框变粗 文字变深
禁用 灰色+低透明度 灰色边框 灰色文字
// 按钮状态示例
class ButtonStatesExample extends StatefulWidget {
  const ButtonStatesExample({super.key});

  
  State<ButtonStatesExample> createState() => _ButtonStatesExampleState();
}

class _ButtonStatesExampleState extends State<ButtonStatesExample> {
  bool _isEnabled = true;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('按钮状态')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 正常状态
            ElevatedButton(
              onPressed: () {},
              child: const Text('正常状态'),
            ),
            const SizedBox(height: 16),

            // 禁用状态
            ElevatedButton(
              onPressed: null,
              child: const Text('禁用状态'),
            ),
            const SizedBox(height: 32),

            // 切换启用/禁用
            ElevatedButton(
              onPressed: () {
                setState(() {
                  _isEnabled = !_isEnabled;
                });
              },
              child: Text(_isEnabled ? '禁用下方按钮' : '启用下方按钮'),
            ),
            const SizedBox(height: 16),

            // 可切换状态的按钮
            ElevatedButton(
              onPressed: _isEnabled ? () {} : null,
              child: Text(_isEnabled ? '可用' : '禁用'),
            ),
          ],
        ),
      ),
    );
  }
}

六、按钮尺寸规范

Material Design为按钮定义了标准的尺寸规范,以确保在不同设备上的一致性和良好的触控体验。小型按钮高度为32dp,内边距水平12,文字大小12sp,适用于紧凑列表;中型按钮高度为36dp,内边距水平16,文字大小14sp,适用于一般操作;大型按钮高度为40dp,内边距水平24,文字大小14sp,适用于表单提交;特大按钮高度为48dp,内边距水平32,文字大小16sp,适用于主要CTA。所有按钮的最小触控区域应该不小于48×48dp,这是Material Design的规范,手机建议44-48dp,平板建议48-56dp,桌面建议40-48dp。

尺寸 高度 内边距 文字大小 使用场景
小型 32dp 水平12 12sp 紧凑列表
中型 36dp 水平16 14sp 一般操作
大型 40dp 水平24 14sp 表单提交
特大 48dp 水平32 16sp 主要CTA
屏幕类型 建议尺寸 说明
手机 44-48dp 触控友好
平板 48-56dp 手指更大
桌面 40-48dp 鼠标操作
// 按钮尺寸示例
class ButtonSizesExample extends StatelessWidget {
  const ButtonSizesExample({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('按钮尺寸')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _buildSizeSection('小型按钮 (32dp)', 32),
            const SizedBox(height: 16),
            _buildSizeSection('中型按钮 (36dp)', 36),
            const SizedBox(height: 16),
            _buildSizeSection('大型按钮 (40dp)', 40),
            const SizedBox(height: 16),
            _buildSizeSection('特大按钮 (48dp)', 48),
          ],
        ),
      ),
    );
  }

  Widget _buildSizeSection(String title, double height) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: const TextStyle(fontSize: 14, color: Colors.grey),
        ),
        const SizedBox(height: 8),
        ElevatedButton(
          style: ElevatedButton.styleFrom(
            minimumSize: Size(200, height),
            padding: const EdgeInsets.symmetric(horizontal: 16),
          ),
          onPressed: () {},
          child: Text('按钮高度: ${height.toInt()}'),
        ),
      ],
    );
  }
}

七、按钮最佳实践

在同一界面中,按钮的组合应该遵循一定的原则。主次分明,使用不同的视觉层次,主按钮用ElevatedButton;数量控制,最多2-3个主按钮,如确认+取消;位置固定,按钮位置保持一致,底部固定或右对齐;间距合理,按钮之间保持足够间距,8-16dp。按钮文案应该使用动作动词,如"提交"、“保存”;简洁明了,最多1-2个词,“确定"优于"我确定”;避免否定,用肯定句,“允许"优于"不禁止”;一致性,相同功能文案一致,所有"删除"都用"删除"。

原则 说明 示例
主次分明 使用不同的视觉层次 主按钮用ElevatedButton
数量控制 最多2-3个主按钮 确认+取消
位置固定 按钮位置保持一致 底部固定或右对齐
间距合理 按钮之间保持足够间距 8-16dp
类型 建议 示例
动作动词 使用动词开头 “提交”、“保存”
简洁明了 最多1-2个词 “确定"优于"我确定”
避免否定 用肯定句 “允许"优于"不禁止”
一致性 相同功能文案一致 所有"删除"都用"删除"
// 按钮最佳实践示例
class ButtonBestPractices extends StatelessWidget {
  const ButtonBestPractices({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('按钮最佳实践')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // 表单提交按钮组合
            const Text(
              '表单提交',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 16),
            Row(
              children: [
                Expanded(
                  child: OutlinedButton(
                    onPressed: () {},
                    child: const Text('清空'),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: OutlinedButton(
                    onPressed: () {},
                    child: const Text('重置'),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  flex: 2,
                  child: ElevatedButton(
                    onPressed: () {},
                    child: const Text('提交'),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 32),

            // 对话框按钮组合
            const Text(
              '对话框',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 16),
            Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                TextButton(
                  onPressed: () {},
                  child: const Text('取消'),
                ),
                const SizedBox(width: 12),
                OutlinedButton(
                  onPressed: () {},
                  child: const Text('稍后'),
                ),
                const SizedBox(width: 12),
                ElevatedButton(
                  onPressed: () {},
                  child: const Text('确认'),
                ),
              ],
            ),
            const SizedBox(height: 32),

            // 危险操作按钮组合
            const Text(
              '危险操作',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 16),
            Row(
              children: [
                Expanded(
                  child: OutlinedButton(
                    style: OutlinedButton.styleFrom(
                      foregroundColor: Colors.red,
                      side: const BorderSide(color: Colors.red),
                    ),
                    onPressed: () {},
                    child: const Text('暂不删除'),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: ElevatedButton(
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.red,
                      foregroundColor: Colors.white,
                    ),
                    onPressed: () {},
                    child: const Text('删除'),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

八、Button样式系统

Flutter的Button组件通过ButtonStyle提供了强大的样式定制能力,可以精细控制按钮的各个视觉属性。ButtonStyle包含Material属性、Mouse属性和其他属性。Material属性包括backgroundColor、foregroundColor、overlayColor、shadowColor、surfaceTintColor和elevation;Mouse属性包括mouseCursor和visualDensity;其他属性包括fixedSize、minimumSize、maximumSize、shape、side、padding和animationDuration。

属性 作用 类型 使用场景 示例值
backgroundColor 背景色 MaterialStateProperty 主题色定制 Colors.blue
foregroundColor 前景色(文字/图标) MaterialStateProperty 对比度调整 Colors.white
overlayColor 悬停/按下时的覆盖色 MaterialStateProperty 交互反馈 Colors.white.withOpacity(0.1)
elevation 阴影高度 MaterialStateProperty 深度感 4.0
shape 按钮形状 MaterialStateProperty 圆角定制 RoundedRectangleBorder
padding 内边距 MaterialStateProperty 尺寸调整 EdgeInsets.symmetric(horizontal: 16)
side 边框 MaterialStateProperty 轮廓按钮 BorderSide(color: Colors.blue)
// ButtonStyle定制示例
class ButtonStyleExample extends StatelessWidget {
  const ButtonStyleExample({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Button样式')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // 主按钮样式
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.blue,
                foregroundColor: Colors.white,
                elevation: 4,
                minimumSize: const Size(200, 48),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(24),
                ),
              ),
              onPressed: () {},
              child: const Text('主要操作'),
            ),
            const SizedBox(height: 16),

            // 圆形按钮
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.red,
                foregroundColor: Colors.white,
                shape: const CircleBorder(),
                fixedSize: const Size(64, 64),
              ),
              onPressed: () {},
              child: const Icon(Icons.add, size: 32),
            ),
            const SizedBox(height: 16),

            // 状态响应按钮
            OutlinedButton(
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.resolveWith((states) {
                  if (states.contains(MaterialState.pressed)) {
                    return Colors.blue.withOpacity(0.1);
                  }
                  return Colors.transparent;
                }),
                foregroundColor: MaterialStateProperty.resolveWith((states) {
                  if (states.contains(MaterialState.pressed)) {
                    return Colors.blue;
                  }
                  return Colors.grey;
                }),
                side: MaterialStateProperty.resolveWith((states) {
                  if (states.contains(MaterialState.pressed)) {
                    return const BorderSide(color: Colors.blue);
                  }
                  return BorderSide(color: Colors.grey.shade300);
                }),
              ),
              onPressed: () {},
              child: const Text('状态响应'),
            ),
            const SizedBox(height: 16),

            // 胶囊按钮
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.green,
                foregroundColor: Colors.white,
                shape: const StadiumBorder(),
                padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
              ),
              onPressed: () {},
              child: const Text('胶囊按钮'),
            ),
            const SizedBox(height: 16),

            // 斜角按钮
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.purple,
                foregroundColor: Colors.white,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(4),
                ),
              ),
              onPressed: () {},
              child: const Text('斜角按钮'),
            ),
          ],
        ),
      ),
    );
  }
}

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐