代码之家  ›  专栏  ›  技术社区  ›  J. Doe

使用指定的圆角边框创建uiview

  •  0
  • J. Doe  · 技术社区  · 6 年前

    我想创建一个具有我指定的圆角边框的uiview。例如,我想创建一个有三个边框的uiview:左、上和右,右上和左上边框应该是圆形的。

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

    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()
        }
    }
    

    但是,我找不到一个很好的方法来为指定的角添加一个角半径。我有一个简单的方法来处理曲线:

    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 回复  |  直到 6 年前
        1
  •  2
  •   matt    6 年前

    你的曲线绘制代码的问题不是曲线太粗,而是直线太细。它们很薄,因为它们轻拍着视图的边缘。所以你的线条宽度是2点,但是其中一点是 在视野之外 . 点不是像素,那么还有什么像素需要填充呢?只有那些 里面 视图。所以直线的可见线宽度为1,只有曲线的可见线宽度为2。

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

    为了演示这一点,我修改了您的代码以在原始代码的插入版本中操作 rect (顺便说一下,这应该是你的观点 界限 ,而不是它的框架):

    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

    正如您所看到的,这缺少屏幕截图的伪影。