Ric*_*oon 13 user-interface rounding cornerradius swiftui
我知道您可以用来.cornerRadius()
对swiftUI视图的所有角进行圆角处理,但是有没有办法只对特定的角部(例如顶部)进行圆角处理?
Nik*_*hal 65
如果您只需要将顶角圆化 - 在 100 种情况中的 99 种情况下,我确信这正是您正在寻找的 - 对于该问题有一个更简单的解决方案。工作原理如下:
.cornerRadius(_:)
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)
结果视图如下所示:
正如您所看到的,它的框架与其内容完美对齐(蓝色边框)。可以使用相同的方法对成对的底角或侧角进行倒圆角。希望这可以帮助!
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(...))
(有关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)
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)
另一个选择(也许更好)实际上是返回到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)
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.
这是针对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
iOS 16+
VStack {
UnevenRoundedRectangle(cornerRadii: .init(bottomTrailing: 50, topTrailing: 50))
.fill(.orange)
.frame(width: 200, height: 100)
}
Run Code Online (Sandbox Code Playgroud)
结果:
最干净的又一个选项(iOS 15+):
.background(Color.orange, in: RoundedRectangle(cornerRadius: 20))
.background(content: { Color.white.padding(.top, 20) })
Run Code Online (Sandbox Code Playgroud)