SwiftUI中的组合动画(Simultaneous, Sequenced, Exclusive)

了解了常见的几种手势后,接下来我们了解一下组合手势的操作,当一个视图存在多个手势的时候,为了避免手势冲突,SwiftUI提供了自定义手势的方法,比如同时进行,顺序进行等等。

以下是一些常见的多种手势组合使用方式:

  • simultaneously(with:):同时使用多个手势,使它们可以同时响应用户的操作。例如,同时使用MagnificationGestureRotationGesture来实现不同的交互效果。
  • sequenced(before:):按顺序使用多个手势,确保它们按照特定的顺序依次执行。例如,先执行LongPressGesture,然后再执行DragGesture
  • exclusively(before:):在特定条件下使用不同的手势。例如,根据某个条件选择性地使用DragGestureTapGesture

simultaneously(with:) 同时进行

下面对一个Image同时添加旋转和放缩的手势,并且在操作的时候两个动画同时进行。
在这里插入图片描述
在上面代码中,我们将之前放缩和旋转动画的手势单独提了出来,定义成两个手势属性,这样更便于管理,也会更好阅读代码。关于放缩和旋转代码部分,在之前的文章已经做了详细的说明,这里就不再赘述了。

定义好两个手势属性后,我们给Image添加.gesture修饰符,并传入下面的组合手势:

magnificationGesture.simultaneously(with: rotationGesture)

或者:

rotationGesture.simultaneously(with: magnificationGesture)

因为是同时进行的两个手势,所以说谁组合谁都一样。

完整代码如下:

struct SimultaneousDemo: View {

  @GestureState private var scalingRatio: CGFloat = 1.0
  @State private var lastRatio: CGFloat = 1.0

  @GestureState private var rotateAngle: Angle = Angle(degrees: 0.0)
  @State private var lastAngle: Angle = Angle(degrees: 0.0)

  var magnificationGesture: some Gesture {
    MagnificationGesture()
      .updating($scalingRatio, body: { value, state, _ in
        state = value
      })
      .onEnded({ value in
        lastRatio *= value
      })
  }

  var rotationGesture: some Gesture {
    RotationGesture()
      .updating($rotateAngle, body: { value, state, _ in
        state = value
      })
      .onEnded({ value in
        let newDegress = lastAngle.degrees + value.degrees
        lastAngle = Angle(degrees: newDegress)
      })
  }

  var body: some View {
    Image("liuyifei")
      .resizable()
      .frame(width: 200, height: 260)
      .scaleEffect(scalingRatio)
      .scaleEffect(lastRatio)
      .rotationEffect(rotateAngle)
      .rotationEffect(lastAngle)
      .gesture(
        rotationGesture
          .simultaneously(with: magnificationGesture)
    )
  }
}

sequenced(before:) 顺序执行

按顺序使用多个手势,确保它们按照特定的顺序依次执行。
例如下面这个示例,先执行LongPressGesture,然后再执行DragGesture
在这里插入图片描述
上面代码中同样是将两个手势单独提出来当作属性处理,另外为了测试效果,设置了最短的长按时间,按住时图片放大,1秒后图片变回原形,长按手势结束,此时拖动手势才生效。

再给Image添加的.gesture修饰符中传入下面的组合手势,这个可是分顺序的。

longPressGesture.sequenced(before: dragGesture)

完整代码如下:

struct SequencedDemo: View {
  @GestureState private var isLongPressing = false

  @State private var dragOffset: CGSize  = .zero
  @State private var position: CGSize = .zero

  var longPressGesture: some Gesture {
    LongPressGesture(minimumDuration: 1)
      .updating($isLongPressing, body: { currentState, state, _ in
        state = currentState
      })
  }

  var dragGesture: some Gesture {
    DragGesture()
      .onChanged({ value in
        dragOffset.width = position.width + value.translation.width
        dragOffset.height = position.height + value.translation.height
      })
      .onEnded({ _ in
        position = dragOffset
      })
  }

  var body: some View {
    Image("liuyifei")
      .resizable()
      .frame(width: 200, height: 260)
      .scaleEffect(isLongPressing ? 1.5 : 1.0)
      .offset(dragOffset)
      .gesture(
        longPressGesture.sequenced(before: dragGesture)
    )
  }
}

exclusively(before:)

这种手势组合方式可以根据条件来决定哪个手势应该被触发,从而实现更灵活的交互效果。

下面我演示如何在一个视图上根据条件选择性地使用DragGestureLongPressGesture手势。
为了证明长按是否生效了,这里加了一个弹框,长按生效后弹框。

在这里插入图片描述
上面的示例中,在.gesture修饰符中添加了:

longPressGesture.exclusively(before: dragGesture)

意思就是优先判断LongPressGesture是否满足,当用户长按视图时,达到长按手势的最短时间后,长按手势生效,此时DragGesture无效;如果未到长按手势的最短时间就拖拽,那么LongPressGesture失效。

之前的文章说过LongPressGesture执行时如果手指移动超过一定距离,那么LongPressGesture就不满足触发条件了,那么就失效了。

完整代码如下:

struct ExclusivelyDemo: View {

  @State private var dragOffset: CGSize  = .zero
  @State private var position: CGSize = .zero
  @State private var isLongPress: Bool = false

  var longPressGesture: some Gesture {
    LongPressGesture(minimumDuration: 1)
      .onEnded { _ in
        isLongPress.toggle()
      }
  }

  var dragGesture: some Gesture {
    DragGesture()
      .onChanged({ value in
        dragOffset.width = position.width + value.translation.width
        dragOffset.height = position.height + value.translation.height
      })
      .onEnded({ _ in
        position = dragOffset
      })
  }


  var body: some View {
    Image("liuyifei")
      .resizable()
      .frame(width: 200, height: 260)
      .offset(dragOffset)
      .gesture(
        longPressGesture
          .exclusively(before: dragGesture)
    )
      .alert(isPresented: $isLongPress, content: {
        Alert(title: Text("LongPress手势响应了"))
      })
  }
}

写在最后

本篇文章主要介绍了三种手势组合方式,并做了举例,组合方式也比较简单,仅供大家参考。

最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

集创北方ICN6211 MIPIDSI桥接到RGB,支持RGB565/RGB888/RGB666

ICN6211描述: ICN6211是一个桥接芯片,它接收MIPIDSI输入并发送RGB输出。MIPIDSI最多支持4个车道,每个车道的最大运行频率为1Gbps;总最大输入带宽为4Gbps;并且还支持MIPI定义的ULPS(超低功耗状态&#xff0…

计算机网络基础 - 计算机网络和因特网(1)

计算机网络基础 计算机网络和因特网什么是 Internet?具体构造的的角度服务角度网络结构 网络边缘网络核心电路交换分组交换概述排队时延和分组丢失转发表和路由选择协议按照有无网络层的连接 分组交换 VS 电路交换 接入网DSL 因特网接入电缆因特网接入光纤到户 FTTH无线接入网…

实现复杂树结构返回(不含子树), 并且结点间建立关联

💡 一句话结: 实现传感器和深度及采集的数值动态对应,将不规则的数据转变成固定列头的一行行数据。 🔑 关键信息点: 通过传感器编号和深度将传感器对应的数值与时间建立关联。使用SpringBootMyBatis框架实现动态查询…

Nginx实现负载均衡与故障检查自动切换

创作灵感来源于个人项目的一个稳定性规划,单节点的项目稳定性方面可能有很大的缺漏,因此需要升级为多节点,保证服务故障后,依然有其他服务可用,不会给前端用户造成影响。 (前面讲选型,想直接看…

亚马逊自养号测评环境搭建技巧:打造防关联底层环境的关键步骤

今天我们要聊的是完全由人工操作的自养号方法,相信有过相关经验的朋友们都清楚,在实现自养号的过程中,所使用的 IP 和浏览器究竟有哪些选择,以及可能会遇到哪些问题。 首先,我们来看看市场上现有的 IP 类型以及可能出现…

全网最全网络基础思维导图合集(38张)

计算机网络基础知识点多且杂,想要系统地学习,思维导图肯定是必不可少的。 今天整理了38张思维导图,帮助你轻松理清思路,快速掌握关键内容。建议你收藏起来慢慢看,在看过之后最好能重新动手画一画,让计算机…

如何获取一个城市或者一个区域的玫瑰风向图?

玫瑰风向图是一种直观展示风向和风速的图形工具,它在气象学、城市规划、农业等领域都有广泛的应用。那么,如何获取某个城市或某个区域的玫瑰风向图呢? 首先,我们可以借助互联网资源获取玫瑰风向图。现代网络技术发达,…

CentOS部署NFS

NFS服务端 部署NFS服务端 sudo yum install -y nfs-utils挂载目录 给 NFS 指定一个存储位置,也就是网络共享目录。一般来说,应该建立一个专门的 /data 目录,方便起见使用临时目录 /tmp/nfs: mkdir -p /tmp/nfs #修改权限 chmo…

vue使用海康的H5视频播放器开发包实时预览监控画面

使用原因 之前用海康的视频WEB插件实现过监控画面在前端页面的实时预览,但是会有两个问题: 1、该插件需要先进行安装,而且每次开机后也要重新启动该插件; 2、使用该插件很难更改其样式,只能使用其自带的窗口&#xff…

JavaSE——类和对象(二)~~封装

目录 一.封装 二.封装扩展之包 三.static成员 四. 代码块 五. 内部类(重要) 大家好呀,我是北纬,接着上节我们继续讲解Java中关于类和对象的相关知识,今天着重给大家介绍一下关于面向对象程序的特性之一——封装。…

【网络安全】网络安全协议的重要性

一.网络安全 1.什么是网络安全 网络安全(Cyber Security)是指网络系统的硬件、软件及其系统中的数据受到保护,不因偶然的或者恶意的原因而遭受到破坏、更改、泄露,系统连续可靠正常地运行,网络服务不中断。 2.网络安…

DQL(数据查询)

目录 1. DQL概念 2. DQL - 编写顺序 3. 基础查询 3.1 查询多个字段 3.2 字段设置别名 3.3 去除重复记录 3.4 案例 4. 条件查询 4.1 语法 4.2 条件 4.3 案例: 5. 聚合函数 5.1 常见的聚合函数: 5.2 语法 5.3 案例: 6. 分组查…

台灯哪个牌子好?五款性价比高的照明品牌分享

在近几年,儿童长时间使用电子产品已成为普遍现象,这无疑增加了视觉负担。其次,现代教育体系下的学习任务之繁重,与80后、90后学生时代相比,有了显著的加重。而且,学习过程对数码设备的依赖性也大大增加&…

知识分享:大数据信用花导致的评分不足多久能恢复

随着金融风控领域越来越科技化,基于大数据技术的金融风控成为了贷前风控不可或缺的重要环节,相信很多人在申贷的时候都听说过大数据信用和综合评分等词语,那大数据信用花导致的评分不足多久能恢复呢?本文带大家一起去了解一下。 首先&#x…

PD协议:引领电子设备充电新时代

随着科技的飞速发展,电子设备已成为我们日常生活中不可或缺的一部分。然而,这些设备的充电问题一直困扰着广大用户。传统的充电方式不仅效率低下,而且存在着安全隐患。为了解决这一问题,USB Implementers Forum(USB-IF…

机器学习-决策树算法

前言 本篇介绍决策树与随机森林的内容,先完成了决策树的部分。 决策树 决策树(Decision Tree)是一种有监督学习的方法,可以同时解决分类和回归问题,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这…

WPF中MVVM架构学习笔记

MVVM架构是一种基于数据驱动的软件开发架构,它将数据模型(Model)、视图(View)和视图模型(ViewModel)三者进行分离,使得开发者可以更加专注于各自领域的开发。其中,Model负…

系统架构师考试(十)

SaaS为在线客服 PaaS为二次开发,比如低代码平台 IaaS 硬件开发 B 是基础设施作为服务 软件架构的概念 架构风格 数据流风格 网络报文是在计算机网络中通过网络传输的数据单元,它是网络通信的基本单位。网络报文包含了发送方和接收方之间传输的数据&…

蛮力法0/1背包问题实验

实验项目1 蛮力法 实验题目 使用蛮力法解决0/1背包问题。 ​ 问题描述:给定n个重量(weight)为{w1, w2, … ,wn}、价值(key)为{v1, v2, … ,vn}的物品和一个**容量为C(contain)**的背包,求这些物品中的一个最有价值的子集,且要能够装到背包中…

第十三期Big Demo Day亮点项目:CCarbon重塑碳交易生态,助力全球绿色发展

第十三期Big Demo Day活动即将于2024年5月28日在香港数码港的CyberArena隆重举行。我们荣幸地宣布,利用区块链技术优化全球碳交易CCarbon项目将亮相,参与精彩的项目路演。本次活动由ZeeprLabs、BiKing Exchange、Gather冠名赞助,Central Rese…