基础入门 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 组件后,你可以轻松创建专业的底部交互界面,为用户提供流畅直观的操作体验。

相关推荐
m0_738185824 小时前
Flutter 鸿蒙化实战:open_app_settings 适配 OpenHarmony,一键跳转系统设置
flutter·华为·harmonyos·鸿蒙
Fate_I_C4 小时前
拆解一个鸿蒙化插件:CPF-Ionic 是如何把 43 个 Capacitor 插件搬上 OpenHarmony 的
华为·harmonyos
m0_738185824 小时前
Flutter 鸿蒙化实战:qr_code_scanner 适配 OpenHarmony,相机扫码实时识别
数码相机·flutter·华为·harmonyos·鸿蒙
梦想不只是梦与想17 小时前
HarmonyOS应用分层架构设计
harmonyos·分层架构·一次开发,多端部署
MardaWang19 小时前
当滚动逃离了框架 ——HarmonyOS Web 与原生混排滚动的冲突本质与解法
harmonyos·arkts·鸿蒙·deveco studio
tsqtsqtsq030920 小时前
DevEco Studio 介绍
harmonyos
传奇开心果编程1 天前
【现代声明式UI学与练】第4课 列表渲染与 key——如何高效渲染列表、key 的作用、列表重排时的状态保持
学习·flutter·react native·ui·swiftui·android jetpack
HwJack201 天前
【共创稿事节】HarmonyOS 7文旅展陈展厅大空间 3DGS 重建的分块策略与拼接踩坑
3d·华为·harmonyos
m0_738185821 天前
Flutter 鸿蒙化实战:media_info 适配 OpenHarmony,媒体信息与缩略图
flutter·华为·harmonyos·鸿蒙·媒体