SwiftUI中实现创建反弹动画

  介绍

SwiftUI中实现创建反弹动画?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

在写动画之前呢先简单回顾一下SwiftUI中动画的几个要点:

    <李>动画是视图发生变化时的渐变效果李 <>李SwiftUI动画分为隐式动画(.animation())与显式动画(withAnimation())两种 <李>隐式动画是给视图加动画,视图所有的能动画的变化都能被隐式动画影响李 <>李显式动画是针对某个变化进行动画,能精准控制。 <李>视图的插入和移除通过过渡(过渡)来做效果,可以组合多个过渡或自定义过渡李 <>李要构建自定义动画,我们需要实现一个可动画的视图修饰器(遵守AnimatableModier协议)或者实现一个GeometryEffect,并将可动画的属性通过animatableData暴露出来李

<强>

反弹动画属于“起始点和终止点相”等的动画,所以不能够通过SwiftUI中内建的动画来实现(因为这个视图从结果来看没有发生变化)

我们先来构建反弹动画修饰器的框架如下:

 struct反弹:AnimatableModifier {
  var animCount: CGFloat=0
  var振幅:CGFloat=10//振幅
  
  var animatableData: CGFloat {
  得到{animCount}
  集{animCount=newValue}
  }
  
  函数体(内容:内容)→一些观点{//改变视图动画
  }
  }

下面一步一步来

实现身体方法,好让乘以每次增加时视图能以反弹的方式进行动画。一次反弹就向是视图上弹起又落下、下面是动画曲线大致的样子:

 SwiftUI中实现创建反弹动画

三角函数是<代码> y=abs (sin (x))>

 struct反弹:AnimatableModifier {
  …
  函数体(内容:内容)→一些观点{
  让抵消:CGFloat=abs(罪(animCount * .pi * 2) *振幅)
  返回的内容。抵消(y:抵消)
  }
  }

测试代码:

 struct BouncingView:视图
  @State var=0
  
  var身体:一些视图{
  按钮(动作:{
  withAnimation(动画。easeInOut(持续时间:1)){
  水龙头+=1
  }
  标签}:{
  RoundedRectangle (cornerRadius: 15)
  .modifier(反弹(animCount: CGFloat(水龙头)))
  })
  .frame(宽度:100,身高:100)
  }
  }

点击按钮,就能弹两次了~ ~

这个,# 8203;<代码> @State var水龙头

, # 8203;其实并没有什么实际的意义,只是为了触发动画。

因为SwiftUI里只有观点的状态发生变化才会触发动画,而无法通过某个事件来触发;而我们的动画是一个初始状态和结束状态相等的情况,并没有状态的变化,所以这里强行把点击的次数作为视图状态的变化来触发动画。

我找了好久有没有更优雅的方式来解决这个问题,然而并没有找到==b

暴露给外面的,# 8203;<代码> animCount ,# 8203;应该是一个Int才对,那么就增加一个,# 8203;<代码>,# 8203;animValue>

 struct反弹:AnimatableModifier {
  让animCount: Int
  var animValue: CGFloat
  var振幅:CGFloat=10//振幅
  
  init (animCount: Int) {
  自我。animCount=animCount
  自我。animValue=CGFloat (animCount)
  }
  
  var animatableData: CGFloat {
  得到{animValue}
  集{animValue=newValue}
  }
  
  函数体(内容:内容)→一些观点{
  让抵消:CGFloat=abs(罪(animValue * .pi * 2) *振幅)
  返回的内容。抵消(y:抵消)
  }
  }

因为,# 8203;<代码>,# 8203;animValue>

为了方便使用,再添加一个视图的扩展方法:

{扩展视图
  func反弹(animCount: Int)→一些观点{
  自我。修饰符(反弹(animCount: animCount))
  }
  }

现在虽然能弹了,但是相对还比较生硬,就想在视图”落地”后再给它增加振幅逐步衰减的几次反弹,一开始尝试了简单的减半反弹,实验证明观感更差,看起来有点难受。

我们实际生活中的反弹的振幅变化应该是符合阻尼正弦波的,参考链接里的公式,修改如下:

 struct反弹:AnimatableModifier {
  让animCount: Int
  var animValue: CGFloat
  var振幅:CGFloat//振幅
  var bouncingTimes: Int
  
  init (animCount: Int,振幅:CGFloat=10, bouncingTimes: Int=3) {
  自我。animCount=animCount
  自我。animValue=CGFloat (animCount)
  自我。振幅=振幅
  自我。bouncingTimes=bouncingTimes
  }
  
  var animatableData: CGFloat {
  得到{animValue}
  集{animValue=newValue}
  }
  
  函数体(内容:内容)→一些观点{
  让t=animValue - CGFloat (animCount)
  让抵消:CGFloat=abs(战俘(CGFloat (M_E) - t) *罪(t * .pi * CGFloat (bouncingTimes)) *振幅)
  返回的内容。抵消(y:抵消)
  }
  }
  
  {扩展视图
  func反弹(animCount: Int,
  振幅:CGFloat=10,
  bouncingTimes: Int=3)→一些观点{
  自我。修饰符(反弹(animCount: animCount,
  振幅,振幅,
  bouncingTimes: bouncingTimes))
  }
  }

SwiftUI中实现创建反弹动画