GragGesture在项目中是常常用到的,尤其是在做一个些炫酷的动画中,比方一些盛行的交际软件,例如:国内的探探,国外的Tinder, 首页都有相似左滑右滑的动效。这些都和Grag手势有关系。下面咱们来一同看看吧。
要想让一个视图动起来,那么咱们能够设置视图的 offset 属性,在视图drag过程中,把这个值不断的更新给offset就能够完成企图跟着手势动起来的作用。
其实,在用法上和上面几节讲的手势办法运用很相似。咱们下面用一个带有圆角的正方形来做比如。
需求
- 圆角视图跟着手势移动
- 当手势结束时,把offset归零
代码如下:
struct DragGestureSample: View {
@State var offset: CGSize = .zero
var body: some View {
Rectangle()
.fill()
.frame(width: 180, height: 180)
.cornerRadius(25)
.offset(offset)
.gesture(
DragGesture()
.onChanged { value in
withAnimation(.spring()) {
offset = value.translation
}
}
.onEnded { value in
withAnimation(.spring()) {
offset = .zero
}
}
)
}
}
在Drag手势中,value参数代表当时拖拽手势的信息,其中value.translation表明拖拽的位移间隔
咱们来复现一下探探的卡片滑动动画。
首要,咱们来剖析一下动画是什么样的。当你向左向右滑动卡片时,卡片会向左、向右移动,其次卡片会有一定的倾斜度,还会有一点缩小的作用。
多观察几回,会发现卡片的作用是多个动画结合的作用。动画包括:
- 位移动画(offset)
- 放缩动画(scale)
- 旋转动画(rotation)
位移作用
位移作用其实和上面的代码和文章开头的比如相同,都是运用offset来接收一个移动中的位置,然后改变视图的位置,首要便是下面的这段代码,即可完成位移,详细原理和上面的相同
@State var offset: CGSize = .zero
.offset(offset)
.gesture(
DragGesture()
.onChanged { value in
withAnimation(.spring()) {
offset = value.translation
}
}
.onEnded { value in
withAnimation(.spring()) {
offset = .zero
}
}
)
放缩作用
当咱们把卡片往边际移动时,就会呈现卡片放缩的状况,假如卡片越接近屏幕左面或右边,卡片放缩的份额就越小。卡片放在屏幕中心时,放缩份额为1.0,默许放缩份额也是1.0
那么,首要问题是怎么核算这个放缩份额。咱们先把根本的代码结构写起来,往.offset办法下面加一行放缩的代码,如下:
.scaleEffect(getScale())
getScale() 是一个办法,回来一个 CGFloat 类型的放缩值。咱们来渐渐调试放缩值
func getScale() -> CGFloat {
let max = UIScreen.main.bounds.width / 2
let offsetX = abs(offset.width)
let percentage = offsetX / max
print("percentage (percentage)")
return 1.0 - percentage
}
思考为啥代码会这样写。
首要,咱们的视图在屏幕中心,咱们向左或许向右能够移动的最大间隔便是屏幕的一半巨细, 咱们用 max 表明。求的视图向左或许向右移动的份额就用当时视图移动的宽度除以max,咱们用percentage表明,就能够得到移动时的放缩份额。abs是取数值的绝对值,由于不管在屏幕的左面或许右边移动的间隔不需要区别正负值,位移由offset来办理,咱们这里只处理放缩份额。
为啥要用1.0 减去percentage?
由于咱们的视图最开始的份额是1.0, 视图在屏幕中心,跟着视图向两边移动,咱们会把视图变小。可是跟着视图向两边移动,咱们能够看到percentage的分母是不变的,那么offsetX会越来越大,越接近屏幕边际,offsetX就会越大。终究percentage会变成1.0,假如不用1减去percentage,作用就会相反,作用便是在屏幕中心是放缩份额是0.0,在两边是1.0
咱们来看看作用。
好像作用不对,能够看到越接近边际,视图就越小,这个没有问题,可是太过于小了。咱们需要限定一个最小份额。限定为 percentage 最小值为 0.5
func getScale() -> CGFloat {
let width = UIScreen.main.bounds.width / 2
let offsetX = abs(offset.width)
let percentage = offsetX / width
let value = 1.0 - min(0.5, percentage)
return value
}
好像作用仍是不太好,咱们能够再把缩放份额调小一点,份额变成原来的0.5倍,让企图的放缩份额变缓慢一点
func getScale() -> CGFloat {
let width = UIScreen.main.bounds.width / 2
let offsetX = abs(offset.width)
let percentage = offsetX / width
return 1.0 - min(0.5, percentage)
}
最终再看看作用:
好像这个作用便是咱们要的作用,现在位移和放缩都有了,接下来咱们看看那旋转动画。
旋转动画
旋转动画的视点核算思路和核算放缩值Scale是相同的,可是略有不同的是,咱们要区别正负值。当咱们向左滑动就要一个负的视点值,让视图向左面倾斜,当咱们向右边滑动时,需要视图向右边倾斜,此刻是一个正值。
.rotationEffect(Angle(degrees: getRotation()))
咱们持续把上面的这段代码放在放缩代码下面,来详细看看getRotation办法
func getRotation() -> Double {
let max = UIScreen.main.bounds.width / 2
let currentWidth = offset.width
let percentage = currentWidth / max
print("percentage (percentage)")
let maxAngle: Double = 10
return Double(percentage * maxAngle)
}
percentage的原理已经解说过了,以及什么需要正负值区别。
为什么要乘以maxAngle?
由于咱们的percentage的最大值通常在[-1.x, 1.x] 之间,为什么这么说,由于咱们的max是固定的屏幕宽度的一半,currentWidth最大值可能会大于max,当你的视图超出屏幕边际时,所以最多percentage也只会大于1一点点, 不会有太多。而假如只是运用percentage作为最终的旋转视点值,那么作用就非常的不显着,所以我乘以10,相当于把视点变大了,作用更显着一些。当然这个值你能够在实践作业中去调整,来达到作业实践场景的需求。
作用如图,仍是很不错的。
以上便是Drag手势的根本介绍,原本还有一个比如。可是介于篇幅太长,我会安排在下一章持续解说另一个比如。
大家有什么观点呢?欢迎留言讨论。
大众号:RobotPBQ