Flutter开发:仿iOS侧滑删除效果的实现

news2024/11/17 21:29:20

前言

在Flutter开发中,基于原生移动端开发的思想也会运用到混合开发中,尤其是原生移动的的好的特性和交互效果更是如此。在现在的发展情况下,Flutter下的混合开发已经越来越替代原生移动的开发,同时也会继承原生开发的优点,那么本文就来分享一下关于Flutter开发中仿iOS原生向左侧滑删除cell的item的效果,记录下来,方便查阅使用。

侧滑删除功能

首先来了解一下侧滑删除功能,移动端实际开发过程中关于侧滑删除的使用是非场景的操作,早期原生app开发的时候侧滑删除功能只有iOS的侧滑删除做的最“丝滑”,直到后来混合开发的兴起以及原生开发的进一步发展,侧滑删除的效果逐渐在各端保持了越来越一致的效果。在app中,最常用的侧滑删除是运用在列表展示,比如侧滑删除列表某一行数据,再比如最常见的聊天记录列表侧滑删除某一条记录等等,这些都是最常用的侧滑删除的使用场景。

Flutter的侧滑删除

在Flutter中,侧滑删除的使用和原生app中的侧滑删除类似,只是使用的控件不一样罢了。Flutter中要想实现侧滑删除,就需要使用控件Dismissble,它是直接实现侧滑删除的功能。Flutter的源码是这样介绍Dismissble的:

A widget that can be dismissed by dragging in the indicated [direction].

上面的源码介绍也就一句话,大概意思就是可以通过在指定的方向上拖动来关闭的小部件。具体的使用下面会介绍到。

侧滑删除实现

实现侧滑删除的功能效果,其实可以分为两个模块:一、实现侧滑出现删除的模块,也就是通过水平滑动平移的控件;二、实现删除按钮的模块,默认时候不显示,只有在滑动侧滑平移之后才显示出来。

那么接下来就来分享一下关于实现Flutter的侧滑删除的功能,这里以常用的向左侧滑删除为例,主要就是Dismissble控件的使用和侧滑显示删除按钮以及通过手势监听水平滑动等功能的实现,具体核心源代码如下所示:

// @dart=2.9

import 'package:flutter/gestures.dart';

import 'package:flutter/material.dart';

import 'package:flutter/cupertino.dart';



void main() {

  runApp(const MyApp());

}



class MyApp extends StatelessWidget {

  const MyApp({Key key}) : super(key: key);



  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      title: 'Flutter Demo',

      theme: ThemeData(

        primarySwatch: Colors.blue,

        visualDensity: VisualDensity.adaptivePlatformDensity,

      ),

      home: const Scaffold(

          body: SlideDelete(),

      ),

    );

  }

}



class Slide extends StatefulWidget {

  List<Widget> actions;

  Widget child;

  double actionsWidth;

  Slide(

      this.child,

      this.actionsWidth,

      this.actions,

      {Key key}

      ) : super(key: key);

  @override

  State<StatefulWidget> createState() {

    return _Slide();

  }

}



class _Slide extends State<Slide> with TickerProviderStateMixin {

  double translateX = 0;

  AnimationController animationController;



  @override

  void initState() {

    super.initState();

    animationController = AnimationController(

        lowerBound: -widget.actionsWidth,

        upperBound: 0,

        vsync: this,

        duration: const Duration(milliseconds: 300)

    )..addListener(() {

      translateX = animationController.value;

      setState(() {

      });

    });

  }

  @override

  Widget build(BuildContext context) {

    return Stack(

      children: <Widget>[

        Positioned.fill(

            child: Row(

              mainAxisAlignment: MainAxisAlignment.end,

              children: widget.actions,

            )),

        GestureDetector(

          onHorizontalDragUpdate: (v){

            onHorizontalDragUpdate(v);

          },



          onHorizontalDragEnd: (v) {

            onHorizontalDragEnd(v);

          },

          child: Transform.translate(

            offset: Offset(translateX, 0),

            child: Row(

              children: <Widget>[

                Expanded(

                  flex: 1,

                  child: widget.child,

                )

              ],

            ),

          ),

        ),



      ],

    );

  }

  void onHorizontalDragUpdate(DragUpdateDetails details) {

    translateX = (translateX + details.delta.dx).clamp(-widget.actionsWidth, 0.0);

    setState(() {

    });

  }



  void onHorizontalDragEnd(DragEndDetails details) {

    animationController.value = translateX;

    if (details.velocity.pixelsPerSecond.dx > 200) {

      close();

    } else if (details.velocity.pixelsPerSecond.dx < -200) {

      open();

    } else {

      if (translateX.abs() > widget.actionsWidth / 2) {

        open();

      } else {

        close();

      }

    }

  }



  void open() {

    if (translateX != -widget.actionsWidth) {

      animationController.animateTo(-widget.actionsWidth);

    }

  }



  void close() {

    if (translateX != 0) {

      animationController.animateTo(0);

    }

  }



  @override

  void dispose() {

    animationController.dispose();

    super.dispose();

  }

}



//左滑出现“删除”效果

class SlideDelete extends StatefulWidget {

  const SlideDelete({Key key}) : super(key: key);



  @override

  State<StatefulWidget> createState() {

    return _SlideDelete();

  }

}



class _SlideDelete extends State<SlideDelete> {

  //确定删除嘛

  bool delete =false;

  @override

  Widget build(BuildContext context) {

    return Center(

      child: Container(

        alignment: Alignment.center,

        height: 70,

        child: Slide(

            GestureDetector(

              onTap: (){},

              child: _createItem(),

            ),

            100,

            <Widget>[

              _createDelete(),

            ]),

      ),

    );

  }



  //左滑删除

  _createDelete() {

    return GestureDetector(

      onTap: () {

        if (delete) {

          print("点击删除");

        } else {

          setState(() {

            delete = !delete;

          });

        }

      },

      child: Container(

        alignment: Alignment.center,

        width: 100,

        color: Colors.red,

        child: Text(delete ?'确定删除' : '删除',style: const TextStyle(fontSize: 14, color: Colors.white, decoration: TextDecoration.none),),

      ),

    );

  }



  //item

  Widget _createItem() {

    return Container(

      color: Colors.white,

      margin: const EdgeInsets.only(left: 4.0),

      child: Padding(

        padding: const EdgeInsets.only(left: 20.0),

        child: Column(

          crossAxisAlignment: CrossAxisAlignment.start,

          mainAxisAlignment: MainAxisAlignment.center,

          children: const <Widget>[

            Text('左滑删除',style: TextStyle(fontSize: 16.0, decoration: TextDecoration.none),),

            SizedBox(height: 5.0,),

          ],

        ),

      ),

    );

  }

}

通过上面的源码可以实现简单的具体的Flutter向左侧滑删除的功能,运行效果如下所示:

 

 

 

 

最后

通过本文关于Flutter开发中仿iOS侧滑删除效果的实现的介绍,想必在以后的Flutter开发中遇到类似的业务需求就会游刃有余,因为在Flutter开发中侧滑删除也是非常常见且重要的使用点。如果认真阅读并且实践示例,尤其是从事Flutter开发不久的开发者来说尤为重要,是一篇值得阅读的文章,且在实际开发中也是必用知识点,所以说这个知识点是必备的,重要性就不在赘述。欢迎关注,一起交流,共同进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/107462.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5年Java经验,定级阿里P7,所有经验全在这份Java核心知识笔记里了

前言 今年的大环境非常差&#xff0c;互联网企业裁员的现象比往年更严重了&#xff0c;可今年刚好是我的第一个“五年计划”截止的时间点&#xff0c;说什么也不能够耽搁了&#xff0c;所以早早准备的跳槽也在疫情好转之后开始进行了。但是&#xff0c;不得不说&#xff0c;这次…

编译和使用hadoop遇到的问题——问题随手记【持续更新】

文章目录编译hadoop遇到的问题java.lang.NoClassDefFoundError: org/apache/hadoop/util/PlatformNamejava.lang.ClassNotFoundException: org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos\$MasterService\$BlockingInterfacejava.lang.ClassNotFoundExceptio…

坚持长期主义 上汽大众ID.纯电品牌迎来加速发展阶段

那些真正能够引领行业发展和变革&#xff0c;并能够持续存活下去的企业&#xff0c;一定是以长期主义作为导向的。 2022年11月&#xff0c;上汽大众ID.纯电家族以月销近万辆、累计销量超10万辆的数据&#xff0c;演绎了一个坚持长期主义汽车大厂的“英雄本色”。长期主义是对抗…

R语言LME4混合效应模型研究教师的受欢迎程度

介绍 最近我们被客户要求撰写关于混合效应模型的研究报告&#xff0c;包括一些图形和统计输出。本教程对多层回归模型进行了基本介绍 。 相关视频&#xff1a;线性混合效应模型(LMM,Linear Mixed Models)和R语言实现 线性混合效应模型(LMM,Linear Mixed Models)和R语言实现…

结构化思维的理解与思考

结构化思维是一种将信息要素从无效转化为有序&#xff0c;提炼核心要点&#xff0c;将信息转化为有结构的知识&#xff0c;更好的帮助大脑理解和记忆&#xff0c;并支持我们清晰表达的通用能力。前言首先&#xff0c;我们先来完成一个游戏&#xff0c;以下有9个计算式&#xff…

微服务应用视角解读如何选择K8S的弹性策略

前言 微服务架构的出现&#xff0c;拆分了庞大的单体应用&#xff0c;让业务之间的开发与协作变得更加灵活。当面临业务流量增加的场景时&#xff0c;往往需要对一些应用组件进行扩容。K8S在应用层面提供了HPA&#xff0c;围绕HPA开源社区延伸出了KEDA这样的弹性组件&#xff…

Compose使用OpenGL+CameraX快速实现相机“拍视频实时滤镜“、”拍照+滤镜“

一、前言 短视频热潮还没有褪去&#xff0c;写这篇文章主要是帮助大部分人&#xff0c;能快速上手实现类似效果&#xff0c;实际上是&#xff1a; CameraX拿相机数据&#xff0c;OpenGL给CameraX提供一个Surface&#xff0c;数据放到OpenGL渲染的线程上去做图像相关操作 Open…

Java项目:springboot+layui就业信息管理

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 该项目采用了spring boot&#xff0c;spring&#xff0c;spring mvc&#xff0c;mybatis作为后端技术框架&#xff0c;这些组合稳定抗打&#x…

Redis缓存穿透、击穿、雪崩到底是个啥?7张图告诉你

目录一、缓存是什么&#xff1f;二、缓存的作用和成本1、缓存的作用&#xff1a;2、缓存的成本&#xff1a;三、缓存作用模型1、根据id查询数据缓存流程四、缓存更新策略1、内存淘汰2、超时剔除3、主动更新五、缓存穿透解决方法&#xff1a;六、缓存雪崩七、缓存击穿1、通过互斥…

基于局部特征和引导形状变形的重叠子宫颈细胞自动分割技术

注&#xff1a;该文为Automatic Segmentation of Overlapping Cervical Smear Cells based on Local Distinctive Features and Guided Shape Deformation的相关阅读注释和翻译 基于局部特征和引导形状变形的重叠子宫颈细胞自动分割技术 概述 提出了一种基于独特的局部特征和…

SpringBoot:模块探究之spring-boot-dependencies

在 SpringBoot 开发时&#xff0c;我们常常会发现一个现象&#xff1a;即在 pom 文件中&#xff0c;加入一个新的依赖&#xff0c;往往不需要引入相应的版本号&#xff08;如下代码块所示&#xff09;&#xff0c;就可以正常引入依赖&#xff0c;这其实是因为我们依赖了 spring…

mysql修改字段的长度是否会锁表

结论&#xff1a; 缩小字段长度不能使用inpalce&#xff0c;会锁表。 放大字段长度&#xff1a;取决于变化前和变化后是否跨越255这个长度。以UTF8编码为例&#xff0c;一个字符占3个字节。 字段变化1&#xff1a;varchar&#xff08;50&#xff09;--》varchar&#xff08;80…

嵌入式:ARM多寄存器存取指令详解

文章目录多寄存器存取指令的二进制编码指令汇编格式举例注意事项多寄存器传送指令可以用一条指令将16个可见寄存器&#xff08;R0~R15&#xff09;的任意子集合&#xff08;或全部&#xff09;存储到存储器或从存储器中读取数据到该寄存器集合中。如&#xff1a;可将寄存器列表…

李书福旗下亿咖通纳斯达克上市:作价38亿美元 路演PPT曝光

雷递网 雷建平 12月21日亿咖通科技控股&#xff08;简称“ECARX”、“亿咖通科技”&#xff09;今日与特殊目的公司COVA Acquisition Corp.&#xff08;简称“COVA”&#xff09;完成合并&#xff0c;并在美国纳斯达克股票市场&#xff08;Nasdaq Stock Market LLC&#xff09;…

[UE5]在多个固定摄像机视角间切换,切换多个摄像机,显示不同摄像机所看内容

[UE5]在多个固定摄像机视角间切换&#xff0c;切换多个摄像机&#xff0c;显示不同摄像机所看内容1.写在前面01.作者碎碎念02.结果演示截图演示视频视频教程源码链接03.实现思路实现思路04.同步的博客CSDN掘金博客园知乎2.需要准备的软件3.步骤大神步骤&#xff1a;详细步骤&am…

再写java探针

大家好&#xff0c;我是烤鸭&#xff1a; 以前写过一篇全链路探针实现的文章&#xff0c;最近同事间搞技术分享&#xff0c;再整理一篇。可惜这两年没有继续搞这方面的技术&#xff0c;算是两年前的拓展篇吧。很多技术只放了图&#xff0c;文字就不写了&#xff0c;可以参考…

笔记本加固态小白怎么设置

​最近有用户说电脑硬盘空间不够用了&#xff0c;于是问笔记本加固态小白怎么设置&#xff0c;打算将系统安装在这上面。但由于原先的系统盘有很多重要的数据&#xff0c;该用户就问到有没有什么办法不需要重装&#xff0c;关于笔记本加固态小白操作方法。 工具/原料&#xff…

Redis集群的三种方式详解(附优缺点及原理区别)

Redis提供了三种集群方式&#xff0c;下面我重点详解Redis三种集群方式的原理及优缺点等区别mikechen 目录 Redis主从复制模式Redis哨兵模式Redis集群模式 Redis主从复制模式 1.Redis主从复制定义 主从模式是三种模式中最简单的&#xff0c;主从模式指的是使用一个Redis实例…

Redis入门及Redis基本数据类型的相关命令

1.1、Redis简介 Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker&#xff0c;翻译为: Redis是一个开源的内存中的数据结构存储系统&#xff0c;它可以用作∶数据库、缓存和消息中间件。官网: https:…

2023,AIGC能赚到钱吗?

2022年&#xff0c;AIGC&#xff08;生成式AI&#xff09;是当之无愧的网红。AI作画在各大社交平台刷屏&#xff0c;ChatGPT火爆国内外出尽了风头&#xff0c;依靠AI生成语音和表情、动作的数字人也频频露脸。2022年12月&#xff0c;Science杂志发布了2022年度科学十大突破&…