GragGesture在项目中是常常用到的,尤其是在做一个些炫酷的动画中,比方一些盛行的交际软件,例如:国内的探探,国外的Tinder, 首页都有相似左滑右滑的动效。这些都和Grag手势有关系。下面咱们来一同看看吧。

要想让一个视图动起来,那么咱们能够设置视图的 offset 属性,在视图drag过程中,把这个值不断的更新给offset就能够完成企图跟着手势动起来的作用。

其实,在用法上和上面几节讲的手势办法运用很相似。咱们下面用一个带有圆角的正方形来做比如。

需求

  1. 圆角视图跟着手势移动
  2. 当手势结束时,把offset归零

DragGesture inSwiftUI

代码如下:

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表明拖拽的位移间隔


咱们来复现一下探探的卡片滑动动画。

首要,咱们来剖析一下动画是什么样的。当你向左向右滑动卡片时,卡片会向左、向右移动,其次卡片会有一定的倾斜度,还会有一点缩小的作用

多观察几回,会发现卡片的作用是多个动画结合的作用。动画包括:

  1. 位移动画(offset)
  2. 放缩动画(scale)
  3. 旋转动画(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

咱们来看看作用。

DragGesture inSwiftUI

好像作用不对,能够看到越接近边际,视图就越小,这个没有问题,可是太过于小了。咱们需要限定一个最小份额。限定为 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
    }

DragGesture inSwiftUI

好像作用仍是不太好,咱们能够再把缩放份额调小一点,份额变成原来的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)
    }

最终再看看作用:

DragGesture inSwiftUI

好像这个作用便是咱们要的作用,现在位移和放缩都有了,接下来咱们看看那旋转动画。

旋转动画

旋转动画的视点核算思路和核算放缩值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,相当于把视点变大了,作用更显着一些。当然这个值你能够在实践作业中去调整,来达到作业实践场景的需求。

DragGesture inSwiftUI

作用如图,仍是很不错的。

以上便是Drag手势的根本介绍,原本还有一个比如。可是介于篇幅太长,我会安排在下一章持续解说另一个比如。

大家有什么观点呢?欢迎留言讨论。
大众号:RobotPBQ