You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中点击按钮创建底部滑起半面板?

在Flutter中实现点击触发滑起式底部组件

方案一:用官方showModalBottomSheet快速实现

这是最省心的方式,官方已经封装好滑入滑出动画,还能自定义内容样式,完全匹配动图里的效果。

核心代码示例

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('滑起组件示例')),
        body: Center(
          child: ElevatedButton(
            onPressed: () {
              showModalBottomSheet(
                context: context,
                // 设置顶部圆角,和动图效果对齐
                shape: const RoundedRectangleBorder(
                  borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
                ),
                // 支持拖拽调整高度或关闭
                isScrollControlled: true,
                builder: (context) {
                  // 自定义滑起组件的内部内容
                  return Container(
                    padding: const EdgeInsets.all(16),
                    height: 300,
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        // 顶部拖拽指示器
                        Center(
                          child: Container(
                            width: 40,
                            height: 4,
                            decoration: BoxDecoration(
                              color: Colors.grey[300],
                              borderRadius: BorderRadius.circular(2),
                            ),
                          ),
                        ),
                        const SizedBox(height: 16),
                        const Text(
                          '操作选项',
                          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                        ),
                        const SizedBox(height: 12),
                        Expanded(
                          child: ListView(
                            children: const [
                              ListTile(title: Text('选项1')),
                              ListTile(title: Text('选项2')),
                              ListTile(title: Text('选项3')),
                              ListTile(title: Text('选项4')),
                            ],
                          ),
                        ),
                      ],
                    ),
                  );
                },
              );
            },
            child: const Text('弹出滑起组件'),
          ),
        ),
      ),
    );
  }
}

关键参数说明

  • shape: 配置顶部圆角,还原动图里的圆角样式
  • isScrollControlled: 设置为true后,组件可拖拽调整高度,也支持内容滚动
  • builder: 自定义滑起组件的所有内容,表单、列表、按钮都能加

方案二:自定义动画实现个性化效果

如果需要更灵活的动画(比如调整滑入速度、自定义曲线),可以用AnimationController和SlideTransition自己实现:

核心代码示例

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: const CustomBottomSlidePage());
  }
}

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

  @override
  State<CustomBottomSlidePage> createState() => _CustomBottomSlidePageState();
}

class _CustomBottomSlidePageState extends State<CustomBottomSlidePage> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Offset> _slideAnimation;
  bool _isSheetShow = false;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 350),
      vsync: this,
    );
    _slideAnimation = Tween<Offset>(
      begin: const Offset(0, 1),
      end: Offset.zero,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Curves.easeOutCubic,
    ));
  }

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

  void _toggleSheet() {
    setState(() {
      _isSheetShow = !_isSheetShow;
    });
    _isSheetShow ? _controller.forward() : _controller.reverse();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('自定义滑起组件')),
      body: Stack(
        children: [
          Center(
            child: ElevatedButton(
              onPressed: _toggleSheet,
              child: const Text('弹出滑起组件'),
            ),
          ),
          // 点击遮罩关闭组件
          if (_isSheetShow)
            GestureDetector(
              onTap: _toggleSheet,
              child: Container(color: Colors.black.withOpacity(0.5)),
            ),
          // 滑起组件本体
          SlideTransition(
            position: _slideAnimation,
            child: _isSheetShow
                ? Container(
                    height: 300,
                    decoration: const BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
                    ),
                    child: Column(
                      children: [
                        const SizedBox(height: 8),
                        Center(
                          child: Container(
                            width: 40,
                            height: 4,
                            decoration: BoxDecoration(
                              color: Colors.grey[300],
                              borderRadius: BorderRadius.circular(2),
                            ),
                          ),
                        ),
                        Expanded(
                          child: ListView(
                            children: const [
                              ListTile(title: Text('自定义选项1')),
                              ListTile(title: Text('自定义选项2')),
                              ListTile(title: Text('自定义选项3')),
                            ],
                          ),
                        ),
                      ],
                    ),
                  )
                : const SizedBox.shrink(),
          ),
        ],
      ),
    );
  }
}

自定义方案优势

  • 完全控制动画的时长、曲线,做出更独特的滑入效果
  • 自定义遮罩层的透明度、点击逻辑
  • 组件显示/隐藏的逻辑更灵活,可结合业务需求调整

内容的提问来源于stack exchange,提问作者Sunken In Time

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 21:30:53