【问题标题】:How can I animate changes to a BezierPath defined custom cornerRadius with SwiftUI?如何使用 SwiftUI 对 BezierPath 定义的自定义cornerRadius 进行动画更改?
【发布时间】:2021-12-25 08:52:37
【问题描述】:

我正在使用以下方法将圆角添加到 x 个角的视图中:

Round Specific Corners SwiftUI

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 修改器和使用上述扩展的自定义 .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)
        }
    }
}

【问题讨论】:

    标签: ios xcode swiftui uibezierpath swiftui-animation


    【解决方案1】:

    问题出在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)
        }
    }
    

    【讨论】:

    • 太好了。非常感谢您的解决方案。效果很好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    • 2019-12-29
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多