放大手势
放大手势常被称为捏合手势,因为常常在用户张开或捏合两个手指时进行识别。通常这个手势实现用于让用户放大或缩小图片。
发送给updating()
、onChanged()
和onEnded()
方法的值是一个CGFloat
,表示乘上当前比例的倍数,得到图片最终的比例,如下例所示。
示例12-9:定义一个MagnificationGesture
手势
struct ContentView: View {
@GestureState private var magnification: CGFloat = 1
@State private var zoom: CGFloat = 1
var body: some View {
Image(.spot1)
.resizable()
.scaledToFit()
.frame(width: 160, height: 200)
.scaleEffect(zoom * magnification)
.gesture(MagnificationGesture()
.updating($magnification) { value, state, transaction in
state = value
}
.onEnded { value in
zoom = zoom * value
}
)
}
}
示例12-9中的代码定义了两个状态,一个用于记录放大倍数,另一个用于存储最终值。这是为了允许用户多次放大或缩小。执行手势时,倍数值存储在magnification
属性中,但zoom
属性的值直到手势完成时才发生改变,因此在下次用户放大或缩小时,新的比例以上次为基准计算。
为设置图片为用户所选比例,我们对Image
视图应用scaleEffect()
修饰符,并通过将zoom
属性值(用户设置的上一个比例)乘上magnification
属性的值(手势所产生的倍数)计算新的比例。结果就是图片根据手指的移动放大或缩小。
✍️跟我一起做:使用示例12-9中的代码更新ContentView.swift
文件。捏合两个手指来放大或缩小。在模拟器或画面中运行应用时,点击键盘上的Option键激活手势。
示例12-9中的示例允许用户任意放在和缩小图片,但大部分情况下我们需要限制视图的比例为合理值或符合应用的目的。要设置这些限制,我们需要在两处控制比例:对视图应用scaleEffect()
修饰符时,以及手势结束最终的比例设置为zoom
属性时。
示例12-10:确定最小和最大比例
struct ContentView: View {
@GestureState private var magnification: CGFloat = 1
@State private var zoom: CGFloat = 1
var body: some View {
Image(.spot1)
.resizable()
.scaledToFit()
.frame(width: 160, height: 200)
.scaleEffect(getCurrentZoom(magnification: magnification))
.gesture(MagnificationGesture()
.updating($magnification) { value, state, transaction in
state = value
}
.onEnded { value in
zoom = getCurrentZoom(magnification: value)
}
)
}
func getCurrentZoom(magnification: CGFloat) -> CGFloat {
let minZoom: CGFloat = 1
let maxZoom: CGFloat = 2
var current = zoom * magnification
current = max(min(current, maxZoom), minZoom)
return current
}
}
本例中,视图的缩放比例限定在最小为1,最大为2。因我们需要执行一些操作来限定比例为这些值,我们将处理移到一个方法getCurrentZoom()
中,在需要时进行调用。该方法定义了最大最小比例这两个常量,然后通过乘上zoom
属性和放大倍数来计算当前值,最后使用min()
和max()
函数来限定最小为1倍,最大为2倍的结果。min()
函数比较当前比例和最大允许比例,返回两者中的最小值(如果值大于2,返回2),而max()
函数比较结果和最小允许比例,返回两者中的最大值(如值小于1,返回1)。getCurrentZoom()
方法由scaleEffect()
修饰符调用,用于设置视图的比例,onEnded()
方法设置最终比例。因此用户可以放大及缩小图片,但最大为2倍,最小为1倍。
✍️跟我一起做:使用示例12-10中的代码更新ContentView
结构体。则可以按minZoom
和maxZoom
常量所设定的限制来设置视图大小。
旋转手势
旋转手势为用户用两根手势触摸屏幕并做环形移动。常用于旋转图片。就像前面的手势一样,如果希望用户多次执行手势,就需要存储两个状态,一个为当前旋转,另一个是最终旋转。手势所生成的值为Angle
类型的结构体。我们之前使用过这个结构体。它包含两个类型方法,一个用角度创建实例(degrees
(Double
)),另一个通过弧度radians
(Double
)),但在我们示例中将通过手势来旋转图片,因此对当前角度加上手势所产生的变化角度。
示例12-11:定义RotationGesture
识别器
struct ContentView: View {
@GestureState private var rotationAngle: Angle = Angle.zero
@State private var rotation: Angle = Angle.zero
var body: some View {
Image(.spot1)
.resizable()
.scaledToFit()
.frame(width: 160, height: 200)
.rotationEffect(rotation + rotationAngle)
.gesture(RotationGesture()
.updating($rotationAngle) { value, state, transaction in
state = value
}