圆角特定SwiftUI

Ric*_*oon 13 user-interface rounding cornerradius swiftui

我知道您可以用来.cornerRadius()对swiftUI视图的所有角进行圆角处理,但是有没有办法只对特定的角部(例如顶部)进行圆角处理?

Nik*_*hal 65

如果您只需要将顶角圆化 - 在 100 种情况中的 99 种情况下,我确信这正是您正在寻找的 - 对于该问题有一个更简单的解决方案。工作原理如下:

  1. 在视图底部添加一些填充
  2. 将所有角都圆化.cornerRadius(_:)
  3. 通过应用相同值的负填充来删除填充
struct OnlyTopRoundedCornersDemo: View {
    let radius = 12 // radius we need
    var body: some View {
        Rectangle()
            .frame(height: 50)
            .foregroundColor(.black)
        .padding(.bottom, radius)
        .cornerRadius(radius)
        .padding(.bottom, -radius)
    }
}
Run Code Online (Sandbox Code Playgroud)

结果视图如下所示:

在此输入图像描述

正如您所看到的,它的框架与其内容完美对齐(蓝色边框)。可以使用相同的方法对成对的底角或侧角进行倒圆角。希望这可以帮助!

  • 如此干净,效果完美! (3认同)

Pet*_*inz 53

视图修饰符使它变得容易:

struct CornerRadiusStyle: ViewModifier {
    var radius: CGFloat
    var corners: UIRectCorner

    struct CornerRadiusShape: 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)
        }
    }

    func body(content: Content) -> some View {
        content
            .clipShape(CornerRadiusShape(radius: radius, corners: corners))
    }
}

extension View {
    func cornerRadius(radius: CGFloat, corners: UIRectCorner) -> some View {
        ModifiedContent(content: self, modifier: CornerRadiusStyle(radius: radius, corners: corners))
    }
}
Run Code Online (Sandbox Code Playgroud)

例子:

在此处输入图片说明

//left Button
.cornerRadius(radius: 6, corners: [.topLeft, .bottomLeft])

//right Button
.cornerRadius(radius: 6, corners: [.topRight, .bottomRight])
Run Code Online (Sandbox Code Playgroud)


kon*_*iki 13

有两个选项,您可以将View搭配使用Path,也可以创建一个自定义Shape。在这两种情况下,您都可以单独使用它们,也可以在.background(RoundedCorders(...))

在此处输入图片说明

选项1:使用Path + GeometryReader

(有关GeometryReader的更多信息:https : //swiftui-lab.com/geometryreader-to-the-rescue/

struct ContentView : View {
    var body: some View {

        Text("Hello World!")
            .foregroundColor(.white)
            .font(.largeTitle)
            .padding(20)
            .background(RoundedCorners(color: .blue, tl: 0, tr: 30, bl: 30, br: 0))
    }
}
Run Code Online (Sandbox Code Playgroud)
struct RoundedCorners: View {
    var color: Color = .blue
    var tl: CGFloat = 0.0
    var tr: CGFloat = 0.0
    var bl: CGFloat = 0.0
    var br: CGFloat = 0.0

    var body: some View {
        GeometryReader { geometry in
            Path { path in

                let w = geometry.size.width
                let h = geometry.size.height

                // Make sure we do not exceed the size of the rectangle
                let tr = min(min(self.tr, h/2), w/2)
                let tl = min(min(self.tl, h/2), w/2)
                let bl = min(min(self.bl, h/2), w/2)
                let br = min(min(self.br, h/2), w/2)

                path.move(to: CGPoint(x: w / 2.0, y: 0))
                path.addLine(to: CGPoint(x: w - tr, y: 0))
                path.addArc(center: CGPoint(x: w - tr, y: tr), radius: tr, startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false)
                path.addLine(to: CGPoint(x: w, y: h - br))
                path.addArc(center: CGPoint(x: w - br, y: h - br), radius: br, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: false)
                path.addLine(to: CGPoint(x: bl, y: h))
                path.addArc(center: CGPoint(x: bl, y: h - bl), radius: bl, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 180), clockwise: false)
                path.addLine(to: CGPoint(x: 0, y: tl))
                path.addArc(center: CGPoint(x: tl, y: tl), radius: tl, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 270), clockwise: false)
            }
            .fill(self.color)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

选项2:自定义形状

struct ContentView : View {
    var body: some View {

        Text("Hello World!")
            .foregroundColor(.white)
            .font(.largeTitle)
            .padding(20)
            .background(RoundedCorners(tl: 0, tr: 30, bl: 30, br: 0).fill(Color.blue))
    }
}

struct RoundedCorners: Shape {
    var tl: CGFloat = 0.0
    var tr: CGFloat = 0.0
    var bl: CGFloat = 0.0
    var br: CGFloat = 0.0

    func path(in rect: CGRect) -> Path {
        var path = Path()

        let w = rect.size.width
        let h = rect.size.height

        // Make sure we do not exceed the size of the rectangle
        let tr = min(min(self.tr, h/2), w/2)
        let tl = min(min(self.tl, h/2), w/2)
        let bl = min(min(self.bl, h/2), w/2)
        let br = min(min(self.br, h/2), w/2)

        path.move(to: CGPoint(x: w / 2.0, y: 0))
        path.addLine(to: CGPoint(x: w - tr, y: 0))
        path.addArc(center: CGPoint(x: w - tr, y: tr), radius: tr,
                    startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false)

        path.addLine(to: CGPoint(x: w, y: h - br))
        path.addArc(center: CGPoint(x: w - br, y: h - br), radius: br,
                    startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: false)

        path.addLine(to: CGPoint(x: bl, y: h))
        path.addArc(center: CGPoint(x: bl, y: h - bl), radius: bl,
                    startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 180), clockwise: false)

        path.addLine(to: CGPoint(x: 0, y: tl))
        path.addArc(center: CGPoint(x: tl, y: tl), radius: tl,
                    startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 270), clockwise: false)

        return path
    }
}
Run Code Online (Sandbox Code Playgroud)


orj*_*orj 9

另一个选择(也许更好)实际上是返回到UIKIt。例如:

struct ButtonBackgroundShape: Shape {

    var cornerRadius: CGFloat
    var style: RoundedCornerStyle

    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
        return Path(path.cgPath)
    }
}
Run Code Online (Sandbox Code Playgroud)


Moj*_*ini 9

Using as a custom modifier

You can use it like a normal modifier:

.cornerRadius(20, corners: [.topLeft, .bottomRight])
Run Code Online (Sandbox Code Playgroud)

Only if you implement a simple extension on View like this:

extension View {
    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
        clipShape( RoundedCorner(radius: radius, corners: corners) )
    }
}
Run Code Online (Sandbox Code Playgroud)

And here is the struct behind this:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

You can also use the shape directly as a clipping mask.

  • 该解决方案比公认的解决方案干净得多。 (49认同)
  • 在ios14之前一直工作正常,底部的视图消失了 (6认同)
  • 它在 iOS14 中不再正常工作,我遇到了一些布局问题。 (4认同)
  • 您知道如何在 macOS(而非 Catalyst)的 SwiftUI 视图中实现这一点吗?看起来“NSRect”没有等效的角对象,并且“NSBezierPath”没有“byRoundingCorners”参数。 (3认同)
  • 查看[这个答案](/sf/answers/4104293161/)自定义边框@SorinLica (2认同)
  • 如果您尝试圆化“ScrollView”的角,则此答案不起作用。/sf/ask/4498165941/ (2认同)
  • 有人给这个人颁奖 (2认同)

Chr*_*isR 9

这是针对macOS的改编:

\n
// defines OptionSet, which corners to be rounded \xe2\x80\x93 same as UIRectCorner\nstruct RectCorner: OptionSet {\n    \n    let rawValue: Int\n        \n    static let topLeft = RectCorner(rawValue: 1 << 0)\n    static let topRight = RectCorner(rawValue: 1 << 1)\n    static let bottomRight = RectCorner(rawValue: 1 << 2)\n    static let bottomLeft = RectCorner(rawValue: 1 << 3)\n    \n    static let allCorners: RectCorner = [.topLeft, topRight, .bottomLeft, .bottomRight]\n}\n\n\n// draws shape with specified rounded corners applying corner radius\nstruct RoundedCornersShape: Shape {\n    \n    var radius: CGFloat = .zero\n    var corners: RectCorner = .allCorners\n\n    func path(in rect: CGRect) -> Path {\n        var path = Path()\n\n        let p1 = CGPoint(x: rect.minX, y: corners.contains(.topLeft) ? rect.minY + radius  : rect.minY )\n        let p2 = CGPoint(x: corners.contains(.topLeft) ? rect.minX + radius : rect.minX, y: rect.minY )\n\n        let p3 = CGPoint(x: corners.contains(.topRight) ? rect.maxX - radius : rect.maxX, y: rect.minY )\n        let p4 = CGPoint(x: rect.maxX, y: corners.contains(.topRight) ? rect.minY + radius  : rect.minY )\n\n        let p5 = CGPoint(x: rect.maxX, y: corners.contains(.bottomRight) ? rect.maxY - radius : rect.maxY )\n        let p6 = CGPoint(x: corners.contains(.bottomRight) ? rect.maxX - radius : rect.maxX, y: rect.maxY )\n\n        let p7 = CGPoint(x: corners.contains(.bottomLeft) ? rect.minX + radius : rect.minX, y: rect.maxY )\n        let p8 = CGPoint(x: rect.minX, y: corners.contains(.bottomLeft) ? rect.maxY - radius : rect.maxY )\n\n        \n        path.move(to: p1)\n        path.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.minY),\n                    tangent2End: p2,\n                    radius: radius)\n        path.addLine(to: p3)\n        path.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.minY),\n                    tangent2End: p4,\n                    radius: radius)\n        path.addLine(to: p5)\n        path.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.maxY),\n                    tangent2End: p6,\n                    radius: radius)\n        path.addLine(to: p7)\n        path.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.maxY),\n                    tangent2End: p8,\n                    radius: radius)\n        path.closeSubpath()\n\n        return path\n    }\n}\n\n// View extension, to be used like modifier:\n// SomeView().roundedCorners(radius: 20, corners: [.topLeft, .bottomRight])\nextension View {\n    func roundedCorners(radius: CGFloat, corners: RectCorner) -> some View {\n        clipShape( RoundedCornersShape(radius: radius, corners: corners) )\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n


Naq*_*med 9

iOS 16+

只需使用UnevenRoundedRectangle

 VStack {
    UnevenRoundedRectangle(cornerRadii: .init(bottomTrailing: 50, topTrailing: 50))
                    .fill(.orange)
                    .frame(width: 200, height: 100)
 }
Run Code Online (Sandbox Code Playgroud)

结果:

在此输入图像描述


one*_*ray 5

最干净的又一个选项(iOS 15+):

.background(Color.orange, in: RoundedRectangle(cornerRadius: 20))
.background(content: { Color.white.padding(.top, 20) })
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述