首页 > 其他分享 >SwiftUI中的组合动画(Simultaneous, Sequenced, Exclusive)

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

时间:2024-05-25 11:26:11浏览次数:21  
标签:Sequenced Exclusive some dragOffset value Simultaneous private var 手势

了解了常见的几种手势后,接下来我们了解一下组合手势的操作,当一个视图存在多个手势的时候,为了避免手势冲突,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手势响应了"))
      })
  }
}

写在最后

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

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

标签:Sequenced,Exclusive,some,dragOffset,value,Simultaneous,private,var,手势
From: https://blog.csdn.net/guoyongming925/article/details/139184677

相关文章

  • ctflearn-writeup(Exclusive Santa)
    https://ctflearn.com/challenge/851在完成这题前最好先下载foremost,unrar,stegsolve等工具首先拿到题目后,先解压得到两个图片文件1.png和3.png两张图片用exiftool,strings,binwalk试过后发现无解于是用关键命令foremost3.png-T(修复破损文件)发现有一个output的文件夹......
  • ORA-01102: cannot mount database in EXCLUSIVE mode的错误解决
    数据库运行环境oracle19c,安装后,启动数据库时报错,如下,经排查解决方法记录如下SQL>startupmountORACLEinstancestarted.TotalSystemGlobalArea2415917880bytesFixedSize   8899384bytesVariableSize  520093696bytesDatabaseBuffers 1879048192bytes......
  • How to connect two pairs of AirPods to one phone simultaneously
    TechStreamingHomeKitchenHealthStyleBeautyGiftsDealsMore REVIEWS  TECHHowtoconnecttwopairsofAirPodstoonephonesimultaneouslyWrittenby AbigailAbesamisDemarest and DevonDelfino; editedby ElenaMatarazzo Updated......
  • SQL Server,Could not obtain exclusive lock on database 'model'
    创建SQLServer数据库时出现错误“Couldnotobtainexclusivelockondatabase'model'”尝试以下方法:1.totryreconnectingtothedatabase.2.Restartingtheservice.3.killingthespidholdingthelock. 执行以下SQL语句来查询:select d.name,resource_type,resour......
  • aqs-exclusive
    我们在使用ReentrantLock进行加锁和释放锁时可能会有好奇,这种加锁释放锁的操作和synchronized有什么区别,所以就会去翻源码,一翻源码才发现这里面的知识别有洞天,因为涉及到并发编程最基础最难理解的部分,其中AbstractQueuedSynchronizer这个类是java.util.concurrent的核心,被称为AQS,......
  • Struct SequenceDemo01
    packagecom.chen.struct;publicclassSequenceDemo01{publicstaticvoidmain(String[]args){System.out.println("hello1");System.out.println("hello2");System.out.println("hello3");System.o......
  • python实现同时给多个变量赋值的方法 Simultaneous Assignments
    SimultaneousAssignmentsx,y=y,x这个赋值的执行流程是什么?python的多元赋值原理是tuple的元组封装(tuplepacking)和序列拆封(sequenceunpacking)。t=12345,54321,'hello!'这是元组封装(tuplepacking)的例子,将多个值放进tuple里。x,y,z=t元组封装(tuplepacking)的......
  • C#中的ConcurrentExclusiveSchedulerPair类
    C#中的ConcurrentExclusiveSchedulerPair类 为什么使用ConcurrentExclusiveSchedulerPair?现实生活中的例子是一个停车场的入口和出口,多辆车可以同时进入和离开停车场,但是只有一个车辆可以进入或离开一次。这时候就需要保证同时只有一个车辆能够访问停车场的入口或出口,避免......
  • SAP CRM One Order 锁定模式用的是 Exclusive Lock
    在SAPCRMWebClientUI上点击Edit按钮后,界面进入可编辑状态:后台SM12事务码观察到锁类型为E,即Exclusivelock,也就是排他锁。其中PRCD_HEAD是Pricing模块抬头级别的数据:CRMOneOrder对应的lockobject名称为:E_CRM_ORDER关于这个叫做prospect的必填......
  • SAP CRM One Order 锁定模式用的是 Exclusive Lock
    在SAPCRMWebClientUI上点击Edit按钮后,界面进入可编辑状态:后台SM12事务码观察到锁类型为E,即Exclusivelock,也就是排他锁。其中PRCD_HEAD是Pricing模块抬头级别的数据:CRMOneOrder对应的lockobject名称为:E_CRM_ORDER关于这个叫做prospect的必填字......