本教程会用 DragGesture 再打造一个我们经常在 app 中见到的交互动画效果,这个效果很有利于提升用户交互体验,相信你在很多 app 中见过这个交互,我们来一起看看具体实现吧
本章节的例子是一个可以上下拖动的登录页面,页面搭建很简单我们就不细讲了,我把代码贴在下面
初始状态
struct DragGestureSample2: View {
var body: some View {
ZStack {
Color.green
.ignoresSafeArea()
SignupView()
}
.ignoresSafeArea(edges: .bottom)
}
}
struct SignupView: View {
var body: some View {
VStack(spacing: 30) {
Image(systemName: "chevron.up")
.padding(.top)
Text("Sign up")
.font(.headline)
.fontWeight(.semibold)
Image(systemName: "flame.fill")
.resizable()
.scaledToFit()
.frame(width: 120, height: 120)
Text("这是我最喜欢的SwiftUI教程,我推荐给所有的的盆友们关注,点赞。也可以关注公众号,每天都会更新新知识哟,公众号:RobotPBQ")
.multilineTextAlignment(.center)
Text("Create an Account".uppercased())
.font(.headline)
.foregroundColor(.white)
.padding()
.padding(.horizontal)
.background(Color.black.cornerRadius(10))
Spacer()
}
.frame(maxWidth: .infinity)
.background(Color.white)
.cornerRadius(30)
}
}
效果如下:
下面我们来开始今天的主题内容。
把页面放置在View的底部
我们把这个登录的页面往下移动到只留出头部的箭头和登录的字样。
可以创建一个 startingOffsetY 变量,用于保存起始值,使用 startingOffsetY 来把页面移动到底部。
@State var startingOffsetY: CGFloat = UIScreen.main.bounds.height * 0.85
SignupView()
.offset(y: startingOffsetY)
移动目标视图
当我们使用 DragGesture 手势拖动页面底部的白色区域时,页面会随着我们的手势来进行页面的上下位移
我们用一个变量来保存当前位移的距离
@State var currentDragOffsetY: CGFloat = 0
在 SignupView 的下面再补充一个Offset
SignupView()
.offset(y: startingOffsetY)
.offset(y: currentDragOffsetY)
.gesture(
DragGesture()
.onChanged { value in
withAnimation(.spring()) {
currentDragOffsetY = value.translation.height
}
}
此时我们已经可以移动 SignupView 视图了。但是你会发现你在拖动的过程中,视图一不小心就不见了。
原因是因为没有处理 onEnded 事件。我们来处理一下
处理结束事件
我们需要再创建一个结束为值的 endingOffsetY 变量。
@State var endingOffsetY: CGFloat = 0
SignupView()
.offset(y: startingOffsetY)
.offset(y: currentDragOffsetY)
.offset(y: endingOffsetY)
.gesture(
DragGesture()
.onChanged { value in
withAnimation(.spring()) {
currentDragOffsetY = value.translation.height
}
}
.onEnded { value in
}
)
处理向上的手势
首先我们需要一个值,代表手指移动页面向上的距离。可以使用一个 Text 来 显示 currentDragOffsetY 的值,观察 currentDragOffsetY 的值来判断向上移动多少距离,就把整个页面全部显示出来。
经过观察判断,我把向上的距离限定为-150
.onEnded { value in
withAnimation(.spring()) {
if currentDragOffsetY < -150 {
endingOffsetY = -startingOffsetY
}
currentDragOffsetY = 0
}
}
页面拖动过程中,越往上 currentDragOffsetY 的值就越小,所以当视图向上的距离小于 -150 时,我们就把 endingOffsetY 的值变成 startingOffsetY 值的负值, 然后吧 currentDragOffsetY 设置为零, 如果不设置为零就会有多个值影响offset。
向上的手势处理好了,但是向下的没有处理,所以还是有问题。
处理向下的手势
试图的位置停留在了顶部,当我们再往下拖动时,当前位移的值 currentDragOffsetY 会越来越大,我们还是让当前拖动值大于150时,就让试图放在起始位置 startingOffsetY,然后要把 endingOffsetY 的值变成零。
同理 currentDragOffsetY 也要变成零。然后来看看整体效果
这种效果,在如今的app中非常常见。快快在你的app中使用起来吧。
大家有什么看法呢?欢迎留言讨论。
公众号:RobotPBQ