为 SwiftUI 中的多值变化贡献动画(Animation Deprecation)
Contributing animation for multi values change in SwiftUI(Animation Deprecation)
所以,我有一些结构可以为我提供很多参数:
struct MyAppearance {
public var offset: CGSize = .zero
public var scale: CGFloat
public var rotation: SwiftUI.Angle
public var xAngle: CGFloat
public var yAngle: CGFloat
public var zAngle: CGFloat
public var blur: CGFloat
public var opacity: Double
public var animation: SwiftUI.Animation?
}
public extension MyAppearance {
func apply<Target: SwiftUI.View>(to view: Target) -> some SwiftUI.View {
view
.scaleEffect(scale)
.rotation3DEffect(rotation, axis: (x: xAngle, y: yAngle, z: zAngle))
.blur(radius: blur)
.opacity(opacity)
.offset(offset)
.animation(animation) // this is the effected line
}
}
按照建议使用 @State
并没有什么意义,因为整个结构用于将其动画应用于同时发生的所有更改。
弃用通知警告虽然很烦人,但在这种情况下我该如何摆脱它?
正如您提到的,您的函数不需要使用状态包装器,但是当您要使用它时,您必须这样做,这里有一个例子:
注意:如果你的值类型相同,你可以在数组中提及它们,但如果它们的类型不同,则需要一一应用。
struct ContentView: View {
@State private var myAppearance: MyAppearance = MyAppearance()
var body: some View {
VStack(spacing: 10.0) {
Spacer()
Text("Hello, world!")
.apply(myAppearance: myAppearance)
Spacer()
Button("update scale") { myAppearance.scale *= 2.0 }
Button("update blur") { updateBlur() }
Button("update scale and blur") { myAppearance.scale *= 2.0; updateBlur() }
Button("reset") { myAppearance.scale = 1.0; myAppearance.blur = 0.0 }
}
.padding()
}
private func updateBlur() {
if (myAppearance.blur == .zero) { myAppearance.blur = 1.0 } else { myAppearance.blur *= 2.0 }
}
}
extension View {
func apply(myAppearance: MyAppearance) -> some View {
return self
.scaleEffect(myAppearance.scale)
.blur(radius: myAppearance.blur)
.scaleEffect(myAppearance.scale)
.rotation3DEffect(myAppearance.rotation, axis: (x: myAppearance.xAngle, y: myAppearance.yAngle, z: myAppearance.zAngle))
.blur(radius: myAppearance.blur)
.opacity(myAppearance.opacity)
.offset(myAppearance.offset)
.animation(myAppearance.animation, value: myAppearance.offset)
.animation(myAppearance.animation, value: [myAppearance.scale, myAppearance.xAngle, myAppearance.yAngle, myAppearance.zAngle, myAppearance.blur])
.animation(myAppearance.animation, value: myAppearance.rotation)
.animation(myAppearance.animation, value: myAppearance.opacity)
}
}
struct MyAppearance {
public var offset: CGSize
public var scale: CGFloat
public var rotation: Angle
public var xAngle: CGFloat
public var yAngle: CGFloat
public var zAngle: CGFloat
public var blur: CGFloat
public var opacity: Double
public var animation: Animation?
init() {
self.offset = .zero
self.scale = 1.0
self.rotation = Angle(degrees: .zero)
self.xAngle = .zero
self.yAngle = .zero
self.zAngle = .zero
self.blur = .zero
self.opacity = 1.0
self.animation = Animation.default
}
init(offset: CGSize, scale: CGFloat, rotation: Angle, xAngle: CGFloat, yAngle: CGFloat, zAngle: CGFloat, blur: CGFloat, opacity: Double, animation: Animation? = nil) {
self.offset = offset
self.scale = scale
self.rotation = rotation
self.xAngle = xAngle
self.yAngle = yAngle
self.zAngle = zAngle
self.blur = blur
self.opacity = opacity
self.animation = animation
}
}
所以,我有一些结构可以为我提供很多参数:
struct MyAppearance {
public var offset: CGSize = .zero
public var scale: CGFloat
public var rotation: SwiftUI.Angle
public var xAngle: CGFloat
public var yAngle: CGFloat
public var zAngle: CGFloat
public var blur: CGFloat
public var opacity: Double
public var animation: SwiftUI.Animation?
}
public extension MyAppearance {
func apply<Target: SwiftUI.View>(to view: Target) -> some SwiftUI.View {
view
.scaleEffect(scale)
.rotation3DEffect(rotation, axis: (x: xAngle, y: yAngle, z: zAngle))
.blur(radius: blur)
.opacity(opacity)
.offset(offset)
.animation(animation) // this is the effected line
}
}
按照建议使用 @State
并没有什么意义,因为整个结构用于将其动画应用于同时发生的所有更改。
弃用通知警告虽然很烦人,但在这种情况下我该如何摆脱它?
正如您提到的,您的函数不需要使用状态包装器,但是当您要使用它时,您必须这样做,这里有一个例子:
注意:如果你的值类型相同,你可以在数组中提及它们,但如果它们的类型不同,则需要一一应用。
struct ContentView: View {
@State private var myAppearance: MyAppearance = MyAppearance()
var body: some View {
VStack(spacing: 10.0) {
Spacer()
Text("Hello, world!")
.apply(myAppearance: myAppearance)
Spacer()
Button("update scale") { myAppearance.scale *= 2.0 }
Button("update blur") { updateBlur() }
Button("update scale and blur") { myAppearance.scale *= 2.0; updateBlur() }
Button("reset") { myAppearance.scale = 1.0; myAppearance.blur = 0.0 }
}
.padding()
}
private func updateBlur() {
if (myAppearance.blur == .zero) { myAppearance.blur = 1.0 } else { myAppearance.blur *= 2.0 }
}
}
extension View {
func apply(myAppearance: MyAppearance) -> some View {
return self
.scaleEffect(myAppearance.scale)
.blur(radius: myAppearance.blur)
.scaleEffect(myAppearance.scale)
.rotation3DEffect(myAppearance.rotation, axis: (x: myAppearance.xAngle, y: myAppearance.yAngle, z: myAppearance.zAngle))
.blur(radius: myAppearance.blur)
.opacity(myAppearance.opacity)
.offset(myAppearance.offset)
.animation(myAppearance.animation, value: myAppearance.offset)
.animation(myAppearance.animation, value: [myAppearance.scale, myAppearance.xAngle, myAppearance.yAngle, myAppearance.zAngle, myAppearance.blur])
.animation(myAppearance.animation, value: myAppearance.rotation)
.animation(myAppearance.animation, value: myAppearance.opacity)
}
}
struct MyAppearance {
public var offset: CGSize
public var scale: CGFloat
public var rotation: Angle
public var xAngle: CGFloat
public var yAngle: CGFloat
public var zAngle: CGFloat
public var blur: CGFloat
public var opacity: Double
public var animation: Animation?
init() {
self.offset = .zero
self.scale = 1.0
self.rotation = Angle(degrees: .zero)
self.xAngle = .zero
self.yAngle = .zero
self.zAngle = .zero
self.blur = .zero
self.opacity = 1.0
self.animation = Animation.default
}
init(offset: CGSize, scale: CGFloat, rotation: Angle, xAngle: CGFloat, yAngle: CGFloat, zAngle: CGFloat, blur: CGFloat, opacity: Double, animation: Animation? = nil) {
self.offset = offset
self.scale = scale
self.rotation = rotation
self.xAngle = xAngle
self.yAngle = yAngle
self.zAngle = zAngle
self.blur = blur
self.opacity = opacity
self.animation = animation
}
}