如何使用 SwiftUI 对 BezierPath 定义的自定义 cornerRadius 进行动画更改?
How can I animate changes to a BezierPath defined custom cornerRadius with SwiftUI?
我正在使用以下方法将圆角添加到 x 个角的视图中:
extension View {
func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
clipShape( RoundedCorner(radius: radius, corners: corners) )
}
}
struct RoundedCorner: Shape {
var radius: CGFloat = .infinity
var corners: UIRectCorner = .allCorners
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}
这个效果很好。不幸的是,当我将此视图动画化为另一个没有任何圆角的框架时,角半径没有动画。所有其他动画工作正常。
为了说明这一点,下面显示了使用标准 .cornerRadius 修饰符和使用上述扩展的自定义 .cornerRadius 修饰符的角半径动画:
struct ContentView: View {
@State var radius: CGFloat = 50
var body: some View {
VStack {
Button {
withAnimation(.easeInOut(duration: 2)) {
if radius == 50 {
radius = 0
} else {
radius = 50
}
}
} label: {
Text("Change Corner Radius")
}
Color.red
.frame(width: 100, height: 100)
.cornerRadius(radius, corners: [.topLeft, .bottomRight])
Color.blue
.frame(width: 100, height: 100)
.cornerRadius(radius)
}
}
}
问题出在 RoundedCorner
结构中。它不是为动画而写的。虽然符合 Shape
协议的结构是可动画的,但如果其中没有 var animatableData
就不会动画,这为系统提供了理解如何为 Shape
制作动画的能力。我不知道为什么不需要实施它,因为它通常很简单,就像在这种情况下一样。
将您的 RoundedCorner
结构更改为以下内容,它将按照您想要的方式进行动画处理:
struct RoundedCorner: Shape {
var radius: CGFloat
var corners: UIRectCorner
var animatableData: CGFloat {
get { return radius }
set { radius = newValue }
}
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}
我正在使用以下方法将圆角添加到 x 个角的视图中:
extension View {
func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
clipShape( RoundedCorner(radius: radius, corners: corners) )
}
}
struct RoundedCorner: Shape {
var radius: CGFloat = .infinity
var corners: UIRectCorner = .allCorners
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}
这个效果很好。不幸的是,当我将此视图动画化为另一个没有任何圆角的框架时,角半径没有动画。所有其他动画工作正常。
为了说明这一点,下面显示了使用标准 .cornerRadius 修饰符和使用上述扩展的自定义 .cornerRadius 修饰符的角半径动画:
struct ContentView: View {
@State var radius: CGFloat = 50
var body: some View {
VStack {
Button {
withAnimation(.easeInOut(duration: 2)) {
if radius == 50 {
radius = 0
} else {
radius = 50
}
}
} label: {
Text("Change Corner Radius")
}
Color.red
.frame(width: 100, height: 100)
.cornerRadius(radius, corners: [.topLeft, .bottomRight])
Color.blue
.frame(width: 100, height: 100)
.cornerRadius(radius)
}
}
}
问题出在 RoundedCorner
结构中。它不是为动画而写的。虽然符合 Shape
协议的结构是可动画的,但如果其中没有 var animatableData
就不会动画,这为系统提供了理解如何为 Shape
制作动画的能力。我不知道为什么不需要实施它,因为它通常很简单,就像在这种情况下一样。
将您的 RoundedCorner
结构更改为以下内容,它将按照您想要的方式进行动画处理:
struct RoundedCorner: Shape {
var radius: CGFloat
var corners: UIRectCorner
var animatableData: CGFloat {
get { return radius }
set { radius = newValue }
}
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}