Flutter---右滑显示删除按钮

效果图

关键控件

Transform.translate - 平移变换组件

基本语法

Dart 复制代码
Transform.translate(
  offset: Offset(dx, dy),  // 必需参数
  child: Widget,           // 要平移的子组件
  transformHitTests: true, // 可选
)

核心参数: offset - 平移偏移量

Dart 复制代码
dx: 水平方向偏移量(正数向右,负数向左)

dy: 垂直方向偏移量(正数向下,负数向上)

滑动中监听

Dart 复制代码
onHorizontalDragStart:  // 滑动开始时触发
onHorizontalDragUpdate: // 滑动过程中连续触发
onHorizontalDragEnd:    // 滑动结束时触发
onHorizontalDragCancel: // 滑动被取消时触发
关键知识点

1.为什么向右滑动details.delta.dx为正数,向左滑动details.delta.dx为负数,

Dart 复制代码
坐标系理解:
在Flutter的滑动事件中:

屏幕坐标系:原点(0,0)在屏幕左上角

X轴:从左到右是正方向

Y轴:从上到下是正方向

delta.dx 的含义:
delta.dx 表示水平方向的位移变化量

正值 = 向右滑动(手指从左边移动到右边)

负值 = 向左滑动(手指从右边移动到左边)


(0,0) 左上角
    ┌─────────────┐
    │             │
    │      +------│----> X轴 (正方向向右)
    │      |      │
    │      ↓      │
    │     Y轴     │
    │ (正方向向下) │
    └─────────────┘
实现步骤

1.定义变量

Dart 复制代码
  double _slideOffset = 0.0; //当前滑动偏移量
  final double _maxSlideDistance = 60.0; // 最大滑动距离,删除按钮的宽度也设置了这个值
  bool _showDeleteButton = false;//是否显示删除按钮提示

2.圆角矩形叠在删除按钮上面,所以要用stack组件,先构建删除按钮

Dart 复制代码
// 删除按钮(在内容下面)
                Positioned.fill(
                  child: Align(
                    alignment: Alignment.centerRight,
                    child: GestureDetector(
                      onTap: (){
                        //删除按钮的点击时间
                        print("点击删除按钮");
                      },
                      child: Container(
                        width: 60,
                        height: 40,
                        decoration: BoxDecoration(
                          color: Colors.red,
                          borderRadius: BorderRadius.circular(20),
                        ),
                        child: Center(
                          child: Icon(
                            Icons.delete,
                            color: Colors.white,
                            size: 20,
                          ),
                        ),
                      ),
                    )
                  ),
                ),

3.定义可滑动的内容

Dart 复制代码
// 可滑动的内容
                GestureDetector(
                  //处理滑动更新
                  onHorizontalDragUpdate: (details) {
                    setState(() {
                      //a -= b;表达式表示:a = a - b
                      //details.delta.dx表示用户手指在X轴移动的距离,向右滑动details.delta.dx为正数,向左滑动details.delta.dx为负数,(补充说明)
                      //从 _slideOffset 中减去 details.delta.dx 的值。
                      _slideOffset -= details.delta.dx;

                      //限制滑动范围
                      if (_slideOffset < 0) _slideOffset = 0; //不能向右移
                      if (_slideOffset > _maxSlideDistance) _slideOffset = _maxSlideDistance; //移动距离不能超过设置的最大滑动距离

                      //显示/隐藏删除按钮的逻辑
                      if (_slideOffset > 20 && !_showDeleteButton) {//左移大于20且删除按钮没有显示的时候
                        _showDeleteButton = true; //显示
                      } else if (_slideOffset < 20 && _showDeleteButton) {
                        _showDeleteButton = false;
                      }
                    });
                  },

                  //处理滑动结束
                  onHorizontalDragEnd: (details) {
                    if (_slideOffset > 30) { //用户左滑的距离大于30,则显示删除按钮
                      _slideOffset = _maxSlideDistance;
                    } else { //否则就不显示删除按钮
                      _slideOffset = 0;
                      _showDeleteButton = false;
                    }
                    setState(() {});
                  },

                  child: Transform.translate( //平移变换组件
                    //offset(dx,dy) //dx表示X轴偏移,dy表示Y轴偏移
                    //Offset(正数, 0)  → 向右移动  ; Offset(负数, 0)  → 向左移动
                    //Offset(10, 0)表示向右移动10像素  ; Offset(-10, 0)表示向左移动10像素  ;Offset(0, 0)表示不移动
                    offset: Offset(-_slideOffset, 0),//注意这里这里有个负号,所以这个小于零变成右移,大于零变成左移
                    child: Container(
                      width: 320,
                      height: 40,
                      decoration: BoxDecoration(
                        color: Color(0xFF1E2134),
                        borderRadius: BorderRadius.circular(20),
                      ),
                      child: Center(
                        child: Text( //通过是否显示删除按钮,来更新文本
                          _showDeleteButton ? "松手删除" : "向右滑动显示删除",
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 16,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),

代码实例

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

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

  @override
  State<StatefulWidget> createState() => _MeditationPageState();
}

class _MeditationPageState extends State<HomePage> with SingleTickerProviderStateMixin {

  double _slideOffset = 0.0; //当前滑动偏移量
  final double _maxSlideDistance = 60.0; // 最大滑动距离,删除按钮的宽度也设置了这个值
  bool _showDeleteButton = false;//是否显示删除按钮提示



  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.transparent,
      body: Container(
        width: double.infinity,
        height: double.infinity,
        child: Center(
          child: Container(
            width: 320,
            margin: EdgeInsets.symmetric(horizontal: 20),
            child: Stack(
              children: [

                // 删除按钮(在内容下面)
                Positioned.fill(
                  child: Align(
                    alignment: Alignment.centerRight,
                    child: GestureDetector(
                      onTap: (){
                        //删除按钮的点击时间
                        print("点击删除按钮");
                      },
                      child: Container(
                        width: 60,
                        height: 40,
                        decoration: BoxDecoration(
                          color: Colors.red,
                          borderRadius: BorderRadius.circular(20),
                        ),
                        child: Center(
                          child: Icon(
                            Icons.delete,
                            color: Colors.white,
                            size: 20,
                          ),
                        ),
                      ),
                    )
                  ),
                ),

                // 可滑动的内容
                GestureDetector(
                  //处理滑动更新
                  onHorizontalDragUpdate: (details) {
                    setState(() {
                      //a -= b;表达式表示:a = a - b
                      //details.delta.dx表示用户手指在X轴移动的距离,向右滑动details.delta.dx为正数,向左滑动details.delta.dx为负数,(补充说明)
                      //从 _slideOffset 中减去 details.delta.dx 的值。
                      _slideOffset -= details.delta.dx;

                      //限制滑动范围
                      if (_slideOffset < 0) _slideOffset = 0; //不能向右移
                      if (_slideOffset > _maxSlideDistance) _slideOffset = _maxSlideDistance; //移动距离不能超过设置的最大滑动距离

                      //显示/隐藏删除按钮的逻辑
                      if (_slideOffset > 20 && !_showDeleteButton) {//左移大于20且删除按钮没有显示的时候
                        _showDeleteButton = true; //显示
                      } else if (_slideOffset < 20 && _showDeleteButton) {
                        _showDeleteButton = false;
                      }
                    });
                  },

                  //处理滑动结束
                  onHorizontalDragEnd: (details) {
                    if (_slideOffset > 30) { //用户左滑的距离大于30,则显示删除按钮
                      _slideOffset = _maxSlideDistance;
                    } else { //否则就不显示删除按钮
                      _slideOffset = 0;
                      _showDeleteButton = false;
                    }
                    setState(() {});
                  },

                  child: Transform.translate( //平移变换组件
                    //offset(dx,dy) //dx表示X轴偏移,dy表示Y轴偏移
                    //Offset(正数, 0)  → 向右移动  ; Offset(负数, 0)  → 向左移动
                    //Offset(10, 0)表示向右移动10像素  ; Offset(-10, 0)表示向左移动10像素  ;Offset(0, 0)表示不移动
                    offset: Offset(-_slideOffset, 0),//注意这里这里有个负号,所以这个小于零变成右移,大于零变成左移
                    child: Container(
                      width: 320,
                      height: 40,
                      decoration: BoxDecoration(
                        color: Color(0xFF1E2134),
                        borderRadius: BorderRadius.circular(20),
                      ),
                      child: Center(
                        child: Text( //通过是否显示删除按钮,来更新文本
                          _showDeleteButton ? "松手删除" : "向右滑动显示删除",
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 16,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),


              ],
            ),
          ),
        ),
      ),
    );
  }
}
相关推荐
ZH15455891316 分钟前
Flutter for OpenHarmony Python学习助手实战:GUI桌面应用开发的实现
python·学习·flutter
一只大侠的侠37 分钟前
Flutter开源鸿蒙跨平台训练营 Day6ArkUI框架实战
flutter·开源·harmonyos
一只大侠的侠1 小时前
Flutter开源鸿蒙跨平台训练营 Day 4实现流畅的下拉刷新与上拉加载效果
flutter·开源·harmonyos
ZH15455891311 小时前
Flutter for OpenHarmony Python学习助手实战:模块与包管理的实现
python·学习·flutter
微祎_2 小时前
Flutter for OpenHarmony:构建一个 Flutter 镜像绘图游戏,对称性认知、空间推理与生成式交互设计
flutter·游戏·交互
消失的旧时光-19433 小时前
从 Kotlin 到 Dart:为什么 sealed 是处理「多种返回结果」的最佳方式?
android·开发语言·flutter·架构·kotlin·sealed
子春一4 小时前
Flutter for OpenHarmony:色彩捕手:基于 CIELAB 色差模型与人眼感知的高保真色彩匹配游戏架构解析
flutter·游戏·架构
ZH15455891314 小时前
Flutter for OpenHarmony Python学习助手实战:数据库操作与管理的实现
python·学习·flutter
Lionel6895 小时前
Flutter 鸿蒙:获取真实轮播图API数据
flutter
千逐685 小时前
《基于 Flutter for OpenHarmony 的沉浸式天气可视化系统设计与实现》
flutter