如何创建带指定圆角边框的可调整大小UIView?
Hey there! I get exactly what you're trying to build— a UIView with only top, left, right borders, plus rounded top corners, and you want to stick with UIBezierPath for performance instead of messing with CALayers. Let's break this down step by step to fix that thick line issue and get the exact result you want.
核心思路
- We'll manually draw a bezier path that only includes the three required borders and two rounded corners
- The key fix for the thick line problem is adjusting the path's position to account for how UIBezierPath centers its stroke, so the line doesn't bleed outside the view bounds
- This approach keeps performance lean since we're using the view's native drawing cycle instead of stacking extra CALayers
具体实现代码
Create a custom UIView subclass (I'll call it PartialRoundedBorderView) with configurable properties and proper path drawing:
import UIKit class PartialRoundedBorderView: UIView { // Make these properties configurable for easy tweaks var borderColor: UIColor = .black { didSet { setNeedsDisplay() } } var borderWidth: CGFloat = 1.0 { didSet { setNeedsDisplay() } } var cornerRadius: CGFloat = 8.0 { didSet { setNeedsDisplay() } } override func draw(_ rect: CGRect) { super.draw(rect) // Critical adjustment: inset the rect by half the border width // This ensures the stroke stays entirely within the view bounds (no overflow) let adjustedRect = rect.insetBy(dx: borderWidth/2, dy: borderWidth/2) let path = UIBezierPath() // Start at the bottom-left corner (end of left border) path.move(to: CGPoint(x: adjustedRect.minX, y: adjustedRect.maxY)) // Draw left border up to the start of the top-left rounded corner path.addLine(to: CGPoint(x: adjustedRect.minX, y: adjustedRect.minY + cornerRadius)) // Add top-left rounded corner arc path.addArc(withCenter: CGPoint(x: adjustedRect.minX + cornerRadius, y: adjustedRect.minY + cornerRadius), radius: cornerRadius, startAngle: .pi, endAngle: .pi * 3/2, clockwise: true) // Draw top border across to the start of the top-right rounded corner path.addLine(to: CGPoint(x: adjustedRect.maxX - cornerRadius, y: adjustedRect.minY)) // Add top-right rounded corner arc path.addArc(withCenter: CGPoint(x: adjustedRect.maxX - cornerRadius, y: adjustedRect.minY + cornerRadius), radius: cornerRadius, startAngle: .pi * 3/2, endAngle: 0, clockwise: true) // Draw right border down to the bottom-right corner path.addLine(to: CGPoint(x: adjustedRect.maxX, y: adjustedRect.maxY)) // Set stroke properties and draw the path borderColor.setStroke() path.lineWidth = borderWidth path.stroke() } }
关键细节解释
- Border inset adjustment: The
adjustedRectline fixes the thick stroke issue. UIBezierPath draws strokes centered on the path line—without this inset, half the border width would lie outside the view, making it look thicker than intended. - Continuous path flow: We draw the path in a single continuous loop (bottom-left → top-left corner → top edge → top-right corner → bottom-right) to avoid gaps or disjointed lines.
- Auto-redraw on changes: The
didSetobservers triggersetNeedsDisplay()whenever you tweak border color, width, or corner radius, so the view updates automatically.
性能优势
Using draw(_ rect:) with UIBezierPath is lightweight and efficient. It integrates directly with the view's native rendering cycle, so the system handles optimizations like clipping and redraws only when necessary. This is far more performant than adding multiple CALayers (like separate border layers and corner masks) especially if you're using multiple instances of this view.
使用示例
You can use this view programmatically or set it as the custom class for a view in Storyboard:
// Example setup in a ViewController let customBorderView = PartialRoundedBorderView(frame: CGRect(x: 50, y: 100, width: 250, height: 180)) customBorderView.borderColor = .systemBlue customBorderView.borderWidth = 2.0 customBorderView.cornerRadius = 12.0 customBorderView.backgroundColor = .systemGray5 view.addSubview(customBorderView)
This will give you exactly the view you want: only top, left, right borders, rounded top corners, clean stroke width, and great performance.
内容的提问来源于stack exchange,提问作者J. Doe

