基础入门 Flutter for OpenHarmony:BottomSheet 底部面板详解

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
🎯 欢迎来到 Flutter for OpenHarmony 社区!本文将深入讲解 Flutter 中 BottomSheet 底部面板的使用方法,带你从基础到精通,掌握这一常用的底部交互组件。


一、BottomSheet 组件概述

在 Flutter for OpenHarmony 应用开发中,BottomSheet(底部面板)是一种从屏幕底部滑出的面板组件,常用于展示菜单、选项、表单或详细信息。BottomSheet 遵循 Material Design 规范,提供流畅的动画效果和直观的交互体验。

📋 BottomSheet 类型

类型 说明 适用场景
Persistent 持久型 一直显示在底部的面板
Modal 模态型 点击后显示,点击遮罩关闭

💡 使用场景:BottomSheet 常用于底部菜单、分享选项、评论列表、设置面板、信息展示等场景。


二、BottomSheet 基础用法

BottomSheet 有两种主要的使用方式:模态底部面板和持久底部面板。理解它们的区别,选择合适的类型,是创建良好用户体验的关键。

2.1 showModalBottomSheet - 模态底部面板

showModalBottomSheet 是最常用的方式,显示一个模态的底部面板。模态意味着面板会覆盖当前界面,用户必须处理面板内容或关闭面板才能继续操作。

dart 复制代码
ElevatedButton(
  onPressed: () {
    showModalBottomSheet(
      context: context,
      builder: (BuildContext context) {
        return Container(
          height: 200,
          color: Colors.white,
          child: const Center(
            child: Text('这是一个底部面板'),
          ),
        );
      },
    );
  },
  child: const Text('显示底部面板'),
)

模态面板的特点:

  • 阻隔操作:面板显示时,背景会有半透明遮罩,阻止用户操作底层界面
  • 自动关闭:点击遮罩区域可以关闭面板
  • 流畅动画:带有从底部滑入的流畅动画效果
  • 适用场景:菜单选择、分享选项、确认对话框等需要用户集中注意力的场景

2.2 showBottomSheet - 持久底部面板

showBottomSheet 在 Scaffold 中显示一个持久的底部面板。持久型面板会一直显示在屏幕底部,用户可以同时操作面板内容和底层界面。

dart 复制代码
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

Scaffold(
  key: _scaffoldKey,
  body: Center(
    child: ElevatedButton(
      onPressed: () {
        _scaffoldKey.currentState?.showBottomSheet(
          (BuildContext context) {
            return Container(
              height: 150,
              color: Colors.blue,
              child: const Center(
                child: Text('持久底部面板'),
              ),
            );
          },
        );
      },
      child: const Text('显示持久底部面板'),
    ),
  ),
)

持久面板的特点:

  • 非阻隔:不会阻止用户操作底层界面
  • 手动关闭 :需要调用 Navigator.pop() 或设置关闭按钮来关闭
  • 多面板共存:可以同时显示多个持久面板
  • 适用场景:工具栏、信息面板、播放控制等需要持续访问的功能

💡 选择建议:如果需要用户专注于面板内容,使用模态面板;如果面板是辅助功能,用户可能需要同时操作主界面,使用持久面板。


三、showModalBottomSheet 常用属性

showModalBottomSheet 提供了丰富的属性,让我们可以定制底部面板的外观和行为。

3.1 backgroundColor - 背景颜色

设置底部面板的背景颜色。

dart 复制代码
showModalBottomSheet(
  context: context,
  backgroundColor: Colors.blue,
  builder: (context) => Container(
    height: 200,
    child: const Center(child: Text('蓝色背景')),
  ),
)

设计建议:

  • 通常使用白色或浅色背景,保持界面的清爽
  • 可以根据应用的主题色选择合适的背景色
  • 确保背景色与文字颜色有足够的对比度

3.2 shape - 形状设置

设置底部面板的形状,通常用于设置圆角,让面板看起来更加现代化和精致。

dart 复制代码
showModalBottomSheet(
  context: context,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.vertical(
      top: Radius.circular(20),
    ),
  ),
  builder: (context) => Container(
    height: 200,
    child: const Center(child: Text('圆角面板')),
  ),
)

圆角设置技巧:

  • 圆角半径通常设置在 16-24px 之间
  • 只设置顶部圆角(top),底部不需要圆角
  • 圆角可以让面板与屏幕边缘自然过渡,提升视觉效果
dart 复制代码
showModalBottomSheet(
  context: context,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.vertical(
      top: Radius.circular(20),
    ),
  ),
  builder: (context) => Container(
    height: 200,
    child: const Center(child: Text('圆角底部面板')),
  ),
)

3.3 isDismissible - 是否可关闭

控制是否可以通过点击遮罩层关闭底部面板。

dart 复制代码
showModalBottomSheet(
  context: context,
  isDismissible: false,  // 不可点击遮罩关闭
  builder: (context) => Container(
    height: 200,
    child: Column(
      children: [
        const Text('必须点击按钮关闭'),
        ElevatedButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('关闭'),
        ),
      ],
    ),
  ),
)

3.4 enableDrag - 是否可拖动

控制是否可以通过拖动关闭底部面板。

dart 复制代码
showModalBottomSheet(
  context: context,
  enableDrag: false,  // 不可拖动关闭
  builder: (context) => Container(
    height: 200,
    child: const Center(child: Text('不可拖动')),
  ),
)

3.5 isScrollControlled - 滚动控制

允许底部面板的高度超过屏幕高度,内容可滚动。

dart 复制代码
showModalBottomSheet(
  context: context,
  isScrollControlled: true,  // 启用滚动控制
  builder: (context) => DraggableScrollableSheet(
    initialChildSize: 0.5,  // 初始高度为屏幕一半
    minChildSize: 0.3,      // 最小高度
    maxChildSize: 0.9,      // 最大高度
    expand: false,
    builder: (context, scrollController) {
      return ListView.builder(
        controller: scrollController,
        itemCount: 50,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('项目 $index'),
          );
        },
      );
    },
  ),
)

📊 showModalBottomSheet 属性速查表

属性 类型 默认值 说明
context BuildContext - 上下文(必填)
builder WidgetBuilder - 面板构建器(必填)
backgroundColor Color? - 背景颜色
shape ShapeBorder? - 形状
isDismissible bool true 是否可点击遮罩关闭
enableDrag bool true 是否可拖动关闭
isScrollControlled bool false 是否启用滚动控制

四、DraggableScrollableSheet 可拖动面板

DraggableScrollableSheet 是一个可拖动的底部面板,用户可以通过拖动调整其高度。

4.1 基础用法

dart 复制代码
Scaffold(
  body: DraggableScrollableSheet(
    initialChildSize: 0.3,  // 初始高度为屏幕30%
    minChildSize: 0.2,      // 最小高度为屏幕20%
    maxChildSize: 0.8,      // 最大高度为屏幕80%
    builder: (context, scrollController) {
      return Container(
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.vertical(
            top: Radius.circular(20),
          ),
        ),
        child: ListView.builder(
          controller: scrollController,
          itemCount: 20,
          itemBuilder: (context, index) {
            return ListTile(title: Text('项目 $index'));
          },
        ),
      );
    },
  ),
)

4.2 完整示例

dart 复制代码
class DraggableSheetExample extends StatelessWidget {
  const DraggableSheetExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('可拖动面板')),
      body: Stack(
        children: [
          // 背景内容
          Container(
            color: Colors.grey[200],
            child: const Center(
              child: Text(
                '拖动下方面板',
                style: TextStyle(fontSize: 24),
              ),
            ),
          ),
          // 可拖动面板
          DraggableScrollableSheet(
            initialChildSize: 0.3,
            minChildSize: 0.15,
            maxChildSize: 0.8,
            builder: (context, scrollController) {
              return Container(
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: const BorderRadius.vertical(
                    top: Radius.circular(20),
                  ),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withOpacity(0.1),
                      blurRadius: 10,
                    ),
                  ],
                ),
                child: Column(
                  children: [
                    // 拖动指示器
                    Container(
                      margin: const EdgeInsets.symmetric(vertical: 12),
                      width: 40,
                      height: 4,
                      decoration: BoxDecoration(
                        color: Colors.grey[300],
                        borderRadius: BorderRadius.circular(2),
                      ),
                    ),
                    const Padding(
                      padding: EdgeInsets.symmetric(horizontal: 16),
                      child: Text(
                        '可拖动面板',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    const Divider(),
                    Expanded(
                      child: ListView.builder(
                        controller: scrollController,
                        itemCount: 30,
                        itemBuilder: (context, index) {
                          return ListTile(
                            leading: Icon(Icons.star, color: Colors.orange),
                            title: Text('项目 $index'),
                          );
                        },
                      ),
                    ),
                  ],
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}

五、实际应用场景

5.1 底部菜单

dart 复制代码
ElevatedButton(
  onPressed: () {
    showModalBottomSheet(
      context: context,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (context) {
        return SafeArea(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ListTile(
                leading: const Icon(Icons.camera_alt),
                title: const Text('拍照'),
                onTap: () {
                  Navigator.pop(context);
                  // 拍照逻辑
                },
              ),
              ListTile(
                leading: const Icon(Icons.photo_library),
                title: const Text('从相册选择'),
                onTap: () {
                  Navigator.pop(context);
                  // 相册选择逻辑
                },
              ),
              ListTile(
                leading: const Icon(Icons.videocam),
                title: const Text('录制视频'),
                onTap: () {
                  Navigator.pop(context);
                  // 录制视频逻辑
                },
              ),
            ],
          ),
        );
      },
    );
  },
  child: const Text('打开菜单'),
)

5.2 分享选项

dart 复制代码
ElevatedButton(
  onPressed: () {
    showModalBottomSheet(
      context: context,
      backgroundColor: Colors.transparent,
      builder: (context) {
        return Container(
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
          ),
          child: SafeArea(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                const Padding(
                  padding: EdgeInsets.all(16),
                  child: Text(
                    '分享到',
                    style: TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                GridView.builder(
                  shrinkWrap: true,
                  physics: const NeverScrollableScrollPhysics(),
                  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 4,
                    childAspectRatio: 1,
                  ),
                  itemCount: _shareOptions.length,
                  itemBuilder: (context, index) {
                    return Column(
                      children: [
                        CircleAvatar(
                          radius: 24,
                          backgroundColor: _shareOptions[index]['color'],
                          child: Icon(_shareOptions[index]['icon']),
                        ),
                        const SizedBox(height: 8),
                        Text(_shareOptions[index]['name']),
                      ],
                    );
                  },
                ),
                const SizedBox(height: 16),
              ],
            ),
          ),
        );
      },
    );
  },
  child: const Text('分享'),
)

5.3 评论列表

dart 复制代码
ElevatedButton(
  onPressed: () {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (context) {
        return DraggableScrollableSheet(
          initialChildSize: 0.6,
          minChildSize: 0.4,
          maxChildSize: 0.95,
          expand: false,
          builder: (context, scrollController) {
            return Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.vertical(
                  top: Radius.circular(20),
                ),
              ),
              child: Column(
                children: [
                  // 拖动指示器
                  Container(
                    margin: const EdgeInsets.symmetric(vertical: 12),
                    width: 40,
                    height: 4,
                    decoration: BoxDecoration(
                      color: Colors.grey[300],
                      borderRadius: BorderRadius.circular(2),
                    ),
                  ),
                  const Padding(
                    padding: EdgeInsets.symmetric(horizontal: 16),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text(
                          '评论 (23)',
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        Icon(Icons.close),
                      ],
                    ),
                  ),
                  const Divider(),
                  Expanded(
                    child: ListView.builder(
                      controller: scrollController,
                      itemCount: 20,
                      itemBuilder: (context, index) {
                        return ListTile(
                          leading: CircleAvatar(
                            child: Text('${index + 1}'),
                          ),
                          title: Text('用户 ${index + 1}'),
                          subtitle: Text('这是一条评论内容'),
                        );
                      },
                    ),
                  ),
                ],
              ),
            );
          },
        );
      },
    );
  },
  child: const Text('查看评论'),
)

5.4 表单输入

dart 复制代码
ElevatedButton(
  onPressed: () {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (context) {
        return Padding(
          padding: EdgeInsets.only(
            bottom: MediaQuery.of(context).viewInsets.bottom,
          ),
          child: Container(
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.vertical(
                top: Radius.circular(20),
              ),
            ),
            padding: const EdgeInsets.all(20),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                const Text(
                  '添加评论',
                  style: TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 16),
                TextField(
                  maxLines: 4,
                  decoration: InputDecoration(
                    hintText: '输入评论内容',
                    border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                  ),
                ),
                const SizedBox(height: 16),
                ElevatedButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: const Text('提交'),
                ),
              ],
            ),
          ),
        );
      },
    );
  },
  child: const Text('添加评论'),
)

六、完整示例代码

下面是一个完整的 Flutter 应用示例,展示 BottomSheet 组件的各种用法。

dart 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(const BottomSheetDemo());
}

class BottomSheetDemo extends StatelessWidget {
  const BottomSheetDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BottomSheet 组件演示',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.dark(
          primary: const Color(0xFF6366F1),
          secondary: const Color(0xFF8B5CF6),
          surface: const Color(0xFF1E293B),
          background: const Color(0xFF0F172A),
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const BottomSheetPage(),
    );
  }
}

class BottomSheetPage extends StatelessWidget {
  const BottomSheetPage({super.key});

  final List<Map<String, dynamic>> _shareOptions = const [
    {'name': '微信', 'icon': Icons.chat, 'color': Colors.green},
    {'name': '朋友圈', 'icon': Icons.group, 'color': Colors.green},
    {'name': '微博', 'icon': Icons.public, 'color': Colors.orange},
    {'name': 'QQ', 'icon': Icons.message, 'color': Colors.blue},
    {'name': '复制链接', 'icon': Icons.link, 'color': Colors.grey},
    {'name': '保存图片', 'icon': Icons.download, 'color': Colors.purple},
    {'name': '举报', 'icon': Icons.report, 'color': Colors.red},
    {'name': '更多', 'icon': Icons.more_horiz, 'color': Colors.grey},
  ];

  void _showBasicBottomSheet(BuildContext context) {
    showModalBottomSheet(
      context: context,
      backgroundColor: Colors.white,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (context) {
        return SafeArea(
          child: Padding(
            padding: const EdgeInsets.all(20),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Container(
                  width: 40,
                  height: 4,
                  margin: const EdgeInsets.only(bottom: 20),
                  decoration: BoxDecoration(
                    color: Colors.grey[300],
                    borderRadius: BorderRadius.circular(2),
                  ),
                ),
                const Text(
                  '底部面板',
                  style: TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 16),
                const Text('这是一个基础的底部面板示例'),
                const SizedBox(height: 16),
                ElevatedButton(
                  onPressed: () => Navigator.pop(context),
                  child: const Text('关闭'),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  void _showMenuBottomSheet(BuildContext context) {
    showModalBottomSheet(
      context: context,
      backgroundColor: Colors.white,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (context) {
        return SafeArea(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const SizedBox(height: 8),
              Container(
                width: 40,
                height: 4,
                decoration: BoxDecoration(
                  color: Colors.grey[300],
                  borderRadius: BorderRadius.circular(2),
                ),
              ),
              ListTile(
                leading: const Icon(Icons.camera_alt, color: Colors.blue),
                title: const Text('拍照'),
                onTap: () => Navigator.pop(context),
              ),
              ListTile(
                leading: const Icon(Icons.photo_library, color: Colors.green),
                title: const Text('从相册选择'),
                onTap: () => Navigator.pop(context),
              ),
              ListTile(
                leading: const Icon(Icons.videocam, color: Colors.purple),
                title: const Text('录制视频'),
                onTap: () => Navigator.pop(context),
              ),
            ],
          ),
        );
      },
    );
  }

  void _showShareBottomSheet(BuildContext context) {
    showModalBottomSheet(
      context: context,
      backgroundColor: Colors.white,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (context) {
        return SafeArea(
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                const Text(
                  '分享到',
                  style: TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 16),
                GridView.builder(
                  shrinkWrap: true,
                  physics: const NeverScrollableScrollPhysics(),
                  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 4,
                    childAspectRatio: 1,
                  ),
                  itemCount: _shareOptions.length,
                  itemBuilder: (context, index) {
                    return Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        CircleAvatar(
                          radius: 24,
                          backgroundColor: _shareOptions[index]['color'],
                          child: Icon(_shareOptions[index]['icon'], color: Colors.white),
                        ),
                        const SizedBox(height: 8),
                        Text(
                          _shareOptions[index]['name'],
                          style: const TextStyle(fontSize: 12),
                        ),
                      ],
                    );
                  },
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0F172A),
      appBar: AppBar(
        title: const Text('BottomSheet 演示'),
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(20),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // 标题区域
              Container(
                padding: const EdgeInsets.all(24),
                decoration: BoxDecoration(
                  gradient: LinearGradient(
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                    colors: [
                      const Color(0xFF6366F1).withOpacity(0.2),
                      const Color(0xFF8B5CF6).withOpacity(0.2),
                    ],
                  ),
                  borderRadius: BorderRadius.circular(20),
                  border: Border.all(
                    color: Colors.white.withOpacity(0.1),
                  ),
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      '📱 BottomSheet',
                      style: TextStyle(
                        fontSize: 28,
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                        letterSpacing: 0.5,
                      ),
                    ),
                    const SizedBox(height: 8),
                    Text(
                      '探索 Flutter for OpenHarmony 中底部面板的各种用法',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.white.withOpacity(0.7),
                        height: 1.5,
                      ),
                    ),
                  ],
                ),
              ),

              const SizedBox(height: 32),

              // 基础面板
              _buildSection(
                title: '基础底部面板',
                icon:Icons.vertical_align_bottom,
                color: Colors.blue,
                child: _buildCard([
                  const Text(
                    '点击按钮显示基础的底部面板',
                    style: TextStyle(
                      fontSize: 14,
                      color: Colors.white70,
                    ),
                  ),
                  const SizedBox(height: 12),
                  ElevatedButton.icon(
                    onPressed: () => _showBasicBottomSheet(context),
                    icon: const Icon(Icons.open_in_full),
                    label: const Text('打开面板'),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.blue,
                      minimumSize: const Size(double.infinity, 48),
                    ),
                  ),
                ]),
              ),

              const SizedBox(height: 24),

              // 底部菜单
              _buildSection(
                title: '底部菜单',
                icon: Icons.menu,
                color: Colors.green,
                child: _buildCard([
                  const Text(
                    '显示包含多个选项的底部菜单',
                    style: TextStyle(
                      fontSize: 14,
                      color: Colors.white70,
                    ),
                  ),
                  const SizedBox(height: 12),
                  ElevatedButton.icon(
                    onPressed: () => _showMenuBottomSheet(context),
                    icon: const Icon(Icons.menu_open),
                    label: const Text('打开菜单'),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.green,
                      minimumSize: const Size(double.infinity, 48),
                    ),
                  ),
                ]),
              ),

              const SizedBox(height: 24),

              // 分享面板
              _buildSection(
                title: '分享面板',
                icon: Icons.share,
                color: Colors.purple,
                child: _buildCard([
                  const Text(
                    '显示分享选项网格',
                    style: TextStyle(
                      fontSize: 14,
                      color: Colors.white70,
                    ),
                  ),
                  const SizedBox(height: 12),
                  ElevatedButton.icon(
                    onPressed: () => _showShareBottomSheet(context),
                    icon: const Icon(Icons.ios_share),
                    label: const Text('打开分享'),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.purple,
                      minimumSize: const Size(double.infinity, 48),
                    ),
                  ),
                ]),
              ),

              const SizedBox(height: 24),

              const SizedBox(height: 80),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildSection({
    required String title,
    required IconData icon,
    required Color color,
    required Widget child,
  }) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Container(
              padding: const EdgeInsets.all(8),
              decoration: BoxDecoration(
                color: color.withOpacity(0.2),
                borderRadius: BorderRadius.circular(10),
              ),
              child: Icon(icon, color: color, size: 20),
            ),
            const SizedBox(width: 12),
            Text(
              title,
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.w600,
                color: Colors.white,
              ),
            ),
          ],
        ),
        const SizedBox(height: 12),
        child,
      ],
    );
  }

  Widget _buildCard(List<Widget> children) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.white.withOpacity(0.03),
        borderRadius: BorderRadius.circular(16),
        border: Border.all(
          color: Colors.white.withOpacity(0.05),
        ),
      ),
      child: Column(
        children: children,
      ),
    );
  }
}

七、总结

BottomSheet 是 Flutter for OpenHarmony 中实现底部交互的核心组件,通过合理使用可以创建流畅的底部面板体验。

🎯 核心要点

  • 模态面板showModalBottomSheet 显示可关闭的底部面板
  • 持久面板showBottomSheet 在 Scaffold 中显示持久面板
  • 样式定制:通过 shape、backgroundColor 等自定义外观
  • 交互控制:isDismissible、enableDrag 控制关闭方式
  • 可拖动面板:DraggableScrollableSheet 提供可拖动的交互体验
  • 滚动控制:isScrollControlled 支持内容滚动

📚 使用建议

场景 推荐方案
选项菜单 showModalBottomSheet
分享面板 showModalBottomSheet + GridView
评论列表 DraggableScrollableSheet
表单输入 showModalBottomSheet + isScrollControlled
长内容展示 DraggableScrollableSheet + ListView

掌握 BottomSheet 组件后,你可以轻松创建专业的底部交互界面,为用户提供流畅直观的操作体验。

相关推荐
RaidenLiu2 小时前
拒绝重写!Flutter Add-to-App 全攻略:让原生应用“渐进式”拥抱跨平台
前端·flutter·前端框架
柒儿吖2 小时前
基于 lycium 在 OpenHarmony 上交叉编译 utfcpp 完整实践
c++·c#·harmonyos
二流小码农2 小时前
鸿蒙开发:独立开发者的烦恼之icon图标选择
android·ios·harmonyos
前端不太难2 小时前
HarmonyOS PC 多窗口最难的一层
华为·状态模式·harmonyos
木斯佳2 小时前
HarmonyOS 6实战(工程应用篇)—从被动响应到主动治理,如何使用HiAppEvent捕捉应用崩溃信息
华为·harmonyos
果粒蹬i2 小时前
【HarmonyOS】RN of HarmonyOS实战开发项目+TanStack缓存策略
缓存·华为·harmonyos
Swift社区2 小时前
HarmonyOS PC 的核心:任务模型
华为·harmonyos
柒儿吖3 小时前
基于 lycium 在 OpenHarmony 上交叉编译 komrad36-CRC 完整实践
c++·c#·harmonyos
柒儿吖3 小时前
基于 lycium 在 OpenHarmony 上交叉编译 cppDES 完整实践
c++·harmonyos