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手势响应了"))
      })
  }
}

写在最后

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

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

  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值