字节笔记本

2026年3月22日

Flutter Slidable - 滑动操作面板组件

本文介绍 flutter_slidable,一个为 Flutter 列表项添加滑动操作面板的强大组件库,支持通过代码控制动画的打开与关闭。在 iOS 和 Android 的原生应用中,滑动列表项显示操作菜单(如删除、归档、分享等)是一种极为常见的交互模式。flutter_slidable 将这种交互模式完美地移植到了 Flutter 平台,并且提供了丰富的动画效果和高度可定制的 API。值得注意的是,本项目是 letsar/flutter_slidable 的一个增强分支,新增了通过代码控制 Slidable 动画的功能。

项目简介

flutter_slidable 是一个获得 Flutter Favorite 认证的包,由 letsar 最初开发,EmadBeltaje 在此基础上进行了功能增强。该库实现了带方向性滑动操作的列表项组件,操作面板可以设置为可关闭(dismissible)。

与原版相比,EmadBeltaje 的分支版本增加了一个关键功能:通过代码获取 Slidable 控制器,从而程序化地控制滑动面板的打开和关闭。这一功能在实际开发中非常实用,比如在长按菜单中触发滑动操作、在表单验证后自动打开操作面板等场景。

核心特性

  • 双方向操作面板:支持左侧/顶部(start)和右侧/底部(end)两个方向的操作面板
  • 可关闭支持:操作面板可以设置为可关闭,用户滑动即可将列表项移除
  • 4 种内置动画效果:Behind Motion、Drawer Motion、Scroll Motion、Stretch Motion,每种都提供独特的视觉体验
  • 2 种内置操作组件SlidableAction 和自定义 Builder,满足常见和高级需求
  • 内置关闭动画:提供流畅的关闭过渡效果
  • 代码控制动画:通过控制器可以在代码中打开或关闭滑动面板,支持自定义持续时间和位置
  • 自动关闭行为:点击操作按钮后自动关闭面板(可覆盖),滚动父级 Scrollable 时自动关闭(可覆盖)
  • 轻松禁用:可随时禁用滑动效果
  • 自定义布局和动画:支持完全自定义操作面板的布局和动画效果

技术栈

  • Flutter/Dart:基于 Flutter 框架开发,纯 Dart 实现
  • 手势系统:基于 Flutter 的手势检测和动画系统
  • 发布平台:通过 pub.dev 发布,是 Flutter Favorite 包
  • 分支增强:基于 letsar/flutter_slidable 进行功能扩展

安装指南

由于本版本是原版 flutter_slidable 的增强分支,安装方式与标准包略有不同。

方式一:从 Git 仓库安装

pubspec.yaml 中添加以下依赖:

yaml
dependencies:
  flutter_slidable:
    git:
      url: https://github.com/EmadBeltaje/flutter_slidable.git

方式二:从 pub.dev 安装原版

如果你不需要代码控制动画的功能,可以直接使用原版:

yaml
dependencies:
  flutter_slidable: <latest_version>

在需要使用的 Dart 文件中导入:

dart
import 'package:flutter_slidable/flutter_slidable.dart';

快速开始

Slidable 组件的基本结构包含三个部分:

  • startActionPane:左侧或顶部的操作面板
  • endActionPane:右侧或底部的操作面板
  • child:未滑动时用户看到的实际内容

每个 ActionPane 包含:

  • motion:定义面板动画效果的组件
  • children:操作按钮列表
  • dismissible:可选的关闭配置

使用示例

基础用法

以下是一个完整的 Slidable 使用示例,展示左右两侧的操作面板:

dart
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';

class SlidableExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Slidable 示例')),
      body: ListView(
        children: [
          Slidable(
            // 为可关闭的 Slidable 指定 key
            key: const ValueKey(0),

            // 左侧操作面板
            startActionPane: ActionPane(
              motion: const ScrollMotion(),
              dismissible: DismissiblePane(onDismissed: () {}),
              children: const [
                SlidableAction(
                  onPressed: doNothing,
                  backgroundColor: Color(0xFFFE4A49),
                  foregroundColor: Colors.white,
                  icon: Icons.delete,
                  label: '删除',
                ),
                SlidableAction(
                  onPressed: doNothing,
                  backgroundColor: Color(0xFF21B7CA),
                  foregroundColor: Colors.white,
                  icon: Icons.share,
                  label: '分享',
                ),
              ],
            ),

            // 右侧操作面板
            endActionPane: const ActionPane(
              motion: ScrollMotion(),
              children: [
                SlidableAction(
                  flex: 2,
                  onPressed: doNothing,
                  backgroundColor: Color(0xFF7BC043),
                  foregroundColor: Colors.white,
                  icon: Icons.archive,
                  label: '归档',
                ),
                SlidableAction(
                  onPressed: doNothing,
                  backgroundColor: Color(0xFF0392CF),
                  foregroundColor: Colors.white,
                  icon: Icons.save,
                  label: '保存',
                ),
              ],
            ),

            // 列表项内容
            child: const ListTile(
              leading: Icon(Icons.person),
              title: Text('滑动我'),
              subtitle: Text('向左或向右滑动查看操作'),
            ),
          ),
        ],
      ),
    );
  }

  void doNothing(BuildContext context) {}
}

通过代码控制动画

这是本分支版本的核心增强功能。通过 onSlidableControllerCreated 回调获取控制器,即可在代码中控制面板的打开和关闭:

dart
SlidableController? _controller;

Slidable(
  endActionPane: ActionPane(
    motion: const BehindMotion(),
    children: [
      SlidableAction(
        onPressed: (_) => print('编辑'),
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
        icon: Icons.edit,
        label: '编辑',
      ),
      SlidableAction(
        onPressed: (_) => print('删除'),
        backgroundColor: Colors.red,
        foregroundColor: Colors.white,
        icon: Icons.delete,
        label: '删除',
      ),
    ],
  ),
  // 获取控制器
  onSlidableControllerCreated: (controller) {
    _controller = controller;
  },
  child: ListTile(title: Text('代码控制示例')),
)

// 在代码中打开左侧操作面板
_controller?.openTo(-0.5, duration: const Duration(seconds: 1));

// 在代码中打开右侧操作面板
_controller?.openTo(0.5, duration: const Duration(milliseconds: 300));

// 关闭面板
_controller?.close();

openTo 方法的参数说明:

  • 负值(如 -0.5):显示左侧操作面板
  • 正值(如 0.5):显示右侧操作面板
  • duration:动画持续时间,可选参数

在列表中使用

Slidable 嵌入到 ListView 中是最常见的使用场景:

dart
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    final item = items[index];
    return Slidable(
      key: ValueKey(item.id),
      startActionPane: ActionPane(
        motion: const BehindMotion(),
        children: [
          SlidableAction(
            onPressed: (_) => _editItem(item),
            backgroundColor: const Color(0xFF21B7CA),
            foregroundColor: Colors.white,
            icon: Icons.edit,
            label: '编辑',
          ),
        ],
      ),
      endActionPane: ActionPane(
        motion: const StretchMotion(),
        dismissible: DismissiblePane(
          onDismissed: () => _deleteItem(item),
        ),
        children: [
          SlidableAction(
            onPressed: (_) => _archiveItem(item),
            backgroundColor: const Color(0xFF7BC043),
            foregroundColor: Colors.white,
            icon: Icons.archive,
            label: '归档',
          ),
          SlidableAction(
            onPressed: (_) => _deleteItem(item),
            backgroundColor: const Color(0xFFFE4A49),
            foregroundColor: Colors.white,
            icon: Icons.delete,
            label: '删除',
          ),
        ],
      ),
      child: ListTile(
        leading: CircleAvatar(child: Text(item.name[0])),
        title: Text(item.name),
        subtitle: Text(item.description),
        trailing: Text(item.date),
      ),
    );
  },
)

使用不同的动画效果

flutter_slidable 提供了 4 种内置动画,通过 ActionPanemotion 参数配置:

dart
// 1. Behind Motion - 操作按钮在内容后面出现
ActionPane(
  motion: const BehindMotion(),
  children: [/* actions */],
)

// 2. Drawer Motion - 操作按钮像抽屉一样展开
ActionPane(
  motion: const DrawerMotion(),
  children: [/* actions */],
)

// 3. Scroll Motion - 操作按钮跟随内容移动
ActionPane(
  motion: const ScrollMotion(),
  children: [/* actions */],
)

// 4. Stretch Motion - 操作按钮拉伸动画
ActionPane(
  motion: const StretchMotion(),
  children: [/* actions */],
)

每种动画都有其独特的视觉风格,可以根据应用的整体设计语言选择最合适的动画效果。Behind Motion 效果简洁优雅,Drawer Motion 提供了层次感,Scroll Motion 类似于 iOS 原生的滑动效果,Stretch Motion 则增添了一丝动感。

迁移说明

如果你正在使用 0.6 版本的 flutter_slidable,可以参考官方迁移指南升级到 1.0 版本:

https://github.com/letsar/flutter_slidable/wiki/Migration-from-version-0.6.0-to-version-1.0.0

主要的变化包括 API 结构的调整、动画系统的重构以及新的配置方式。

项目链接

分享: