Use the drag values and use them as a progress to animate views in SwiftUI.
在 SwiftUI 中利用拖拽值控制视图的动画过程。
1. 解决上一节的遗留问题(1)在 Home.swift 中给 ZStack 中的 MenuView 添加背景
MenuView()
.background(Color.black.opacity(0.01)) // 透明度是为了不显示但是能点击交互
(2)如果将透明度改为 1,会发现偏移的还不够,所以修改偏移量
.offset(y: showProfile ? 0 : 1000)
这个 1000 是硬编码,下一节我们会调整为按屏幕尺寸计算,这样无论多大的屏幕都能正常偏移了。
(3)给背景加上手势,这样就可以关闭 MenuView 了。
MenuView()
.background(Color.black.opacity(0.001)) // 透明度是为了不显示但是能点击交互
.offset(y: showProfile ? 0 : 1000)
.animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0))
.onTapGesture {
self.showProfile.toggle() // 关闭视图
}
视频的本意是,单击上面旋转后的 VStack 来关闭,但是这样写的结果是,几乎单击任何地方都关闭。另外,如果那个背景的透明度改成了 0 ,那么点击将不再起作用了。
2. 创建 MenuView 的拖动进程动画(1)还记得前面做拖动卡片组的做法吗?对,要有个状态来协助一下。所以,增加一个状态先。
@State var viewState = CGSize.zero // 视图位置的状态,用来协助 MenuView 的拖动
(2)在 MenuView 组件的最后加上拖动手势,再增加一个偏移修饰让卡片能随手势移动。在手势结束时,检查移动量,超过 50 的时候,关闭 MenuView 组件。
MenuView()
.background(Color.black.opacity(0.01)) // 透明度是为了不显示但是能点击交互
.offset(y: showProfile ? 0 : 1000) // showProfile 为 false 时隐藏
.offset(y: viewState.height) // 跟随拖动改变偏移
.animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0))
.onTapGesture {
self.showProfile.toggle() // 关闭视图
}
.gesture(
DragGesture().onChanged { value in // 拖动手势,参见第 5 节
self.viewState = value.translation
}
.onEnded { value in
if self.viewState.height > 50 { // 向下拖动超过 50 时,关闭组件
self.showProfile = false
}
self.viewState = .zero
}
(3)修改 VStack 的 3D 旋转效果来响应 MenuView 的拖动
.rotation3DEffect(Angle(degrees: showProfile ? (Double(viewState.height) / 10 - 10) : 0), axis: (x: 10, y: 0, z: 0))
小窍门:了解返回值类型
按照⌥
键点击需要查看的部分,如果有帮助显示出来,看上面 :
后面的内容就是类型。如:
var height: CGFloat
说明返回值的类型是 CGFloat
这里首先要注意的是,viewState.height 的值类型是 CGFloat。而 showProfile 需要的类型是 Double,所以必须将 height 的类型强制转换后才能使用(Swift 规定不同类型的值不能进行运算!!!
)。另外就是这个 rotation3DEffect()
是 View 的一个方法,文档超级简单,没有参数说明。也许人家都说英语的就不用写了,但是大叔看不懂啊~~~囧