简体   繁体   English

如何使用 SwiftUI 对 BezierPath 定义的自定义 cornerRadius 的更改进行动画处理?

[英]How can I animate changes to a BezierPath defined custom cornerRadius with SwiftUI?

I am using the following approach to add rounded corners to a view on x number of corners:我正在使用以下方法将圆角添加到 x 个角的视图中:

Round Specific Corners SwiftUI 圆角 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)
    }
}

This works very well.这非常有效。 Unfortunately when I animate this view to another Frame without any rounded corners there is no animation for the cornerRadius.不幸的是,当我将此视图设置为另一个没有任何圆角的 Frame 时,cornerRadius 没有动画。 All other animations work fine.所有其他动画工作正常。

To Illustrate this, the following shows the corner radius animation with the standard .cornerRadius modifier and with the custom .cornerRadius modifier using the extension above:为了说明这一点,以下显示了使用标准 .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)
        }
    }
}

在此处输入图片说明

The issue is in the RoundedCorner struct.问题出在RoundedCorner结构中。 It was not written with animations in mind.它不是在考虑动画的情况下编写的。 While a struct conforming to the Shape protocol is animatable, it won't animate without a var animatableData in it that provides the ability for the system to understand how to animate the Shape .虽然符合Shape协议的结构是可动画的,但如果没有var animatableData为系统提供了解如何为Shape设置动画的能力,它就不会动画。 I don't know why it isn't required to be implemented, because it is usually pretty trivial to do, as in this case.我不知道为什么不需要实现它,因为它通常很简单,就像在这种情况下一样。

Change your RoundedCorner struct to the following, and it will animate like you want it to: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)
    }
}

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM