使用圆角指定边框创建UIView

时间:2018-05-27 18:45:53

标签: swift uibezierpath

我想创建一个具有我已指定的圆形边框的UIView。例如,我想创建一个有3个边框的UIView:left,top和right,topright和topleft border应该是圆角的。

这让我创建了可调整大小的边框视图(没有圆角):

open class ResizableViewBorder: UIView {

    open override func layoutSubviews() {
        super.layoutSubviews()
        setNeedsDisplay()
    }

    open override func draw(_ rect: CGRect) {
        let edges = ... get some UIRectEdges here
        let lineWidth = 1

        if edges.contains(.top) || edges.contains(.all) {
           addBezierPath(paths: [
                CGPoint(x: 0, y: 0 + lineWidth / 2),
                CGPoint(x: self.bounds.width, y: 0 + lineWidth / 2)
                ])
        }

        if edges.contains(.bottom) || edges.contains(.all) {
            addBezierPath(paths: [
                CGPoint(x: 0, y: self.bounds.height - lineWidth / 2),
                CGPoint(x: self.bounds.width, y: self.bounds.height - lineWidth / 2)
                ])
        }

        if (edges.contains(.left) || edges.contains(.all) || edges.contains(.right)) && CurrentDevice.isRightToLeftLanguage{
            addBezierPath(paths: [
                CGPoint(x: 0 + lineWidth / 2, y: 0),
                CGPoint(x: 0 + lineWidth / 2, y: self.bounds.height)
                ])
        }

        if (edges.contains(.right) || edges.contains(.all) || edges.contains(.left)) && CurrentDevice.isRightToLeftLanguage{
            addBezierPath(paths: [
                CGPoint(x: self.bounds.width - lineWidth / 2, y: 0),
                CGPoint(x: self.bounds.width - lineWidth / 2, y: self.bounds.height)
                ])
        }
    }

    private func addBezierPath(paths: [CGPoint]) {
        let lineWidth = 1
        let borderColor = UIColor.black
        let path = UIBezierPath()
        path.lineWidth = lineWidth
        borderColor.setStroke()
        UIColor.blue.setFill()
        var didAddedFirstLine = false
        for singlePath in paths {
            if !didAddedFirstLine {
                didAddedFirstLine = true
                path.move(to: singlePath)
            } else {
                path.addLine(to: singlePath)
            }
        }
        path.stroke()
    }
}

但是,我找不到一个很好的方法来将角半径添加到指定的角落。我有一个hacky方式用曲线做到这一点:

let path = UIBezierPath()
path.lineWidth = 2
path.move(to: CGPoint(x: fakeCornerRadius, y: 0))
path.addLine(to: CGPoint(x: frame.width - fakeCornerRadius, y: 0))
path.addQuadCurve(to: CGPoint(x: frame.width, y: fakeCornerRadius), controlPoint: CGPoint(x: frame.width, y: 0))
path.addLine(to: CGPoint(x: frame.width, y: frame.height - fakeCornerRadius))
path.stroke()

这给了我这个:

enter image description here

为什么四线曲线的那条线如此胖?我更喜欢使用UIBezierPaths而不是CALayers,因为CALayers会对性能产生巨大的影响......

1 个答案:

答案 0 :(得分:2)

曲线绘制代码的错误不在于曲线是胖的,而是直线很薄。它们很薄,因为它们在视图边缘轻拍。所以你的线宽是2点,但其中一个点是视图外的 。并且点不是像素,那么还有哪些像素可以填充?只有里面的视图。因此,直线的可见线宽明显为1,只有曲线的可见线宽为2。

另一个问题是您可能正在查看在计算机上的模拟器中运行的此应用程序。但是模拟器的像素与计算机显示器的像素之间存在不匹配。这会导致大量的绘图工件。精确检查绘图到像素级别的方法是使用模拟器应用程序的屏幕截图图像工具,并查看生成的图像文件,全尺寸,预览或类似。或者在设备上运行并在那里拍摄屏幕截图。

为了证明这一点,我修改了您的代码,以便在原始rect的插入版本中进行操作(顺便说一句,这应该是您的视图&#39> 界限,而不是它的框架):

let fakeCornerRadius : CGFloat = 20
let rect2 = self.bounds.insetBy(dx: 2, dy: 2)
let path = UIBezierPath()
path.lineWidth = 2
path.move(
    to: CGPoint(x: rect2.minX + fakeCornerRadius, y: rect2.minY))
path.addLine(
    to: CGPoint(x: rect2.maxX - fakeCornerRadius, y: rect2.minY))
path.addQuadCurve(
    to: CGPoint(x: rect2.maxX, y: rect2.minY + fakeCornerRadius),
    controlPoint: CGPoint(x: rect2.maxX, y: rect2.minY))
path.addLine(
    to: CGPoint(x: rect2.maxX, y: rect2.maxY - fakeCornerRadius))
path.stroke()

从模拟器应用程序中截取屏幕截图,我得到了这个:

enter image description here

如您所见,这缺少了屏幕截图的伪影。