【问题标题】:Fill a UIView with diagonally drawn lines?用对角线绘制的线条填充 UIView?
【发布时间】:2016-06-15 12:03:53
【问题描述】:

如何像这样填充UIView(带有一些对角线绘制的白线)。

PS:我的意图是关于填充而不是边框​​。

有什么帮助吗?

【问题讨论】:

    标签: ios uiview core-graphics


    【解决方案1】:

    实现此目的的一种方法是覆盖UIViewdraw(_:) 方法并在那里进行自定义绘图。

    绘制对角线相当简单,您只需要:

    • 从 0 到 width + height(沿着矩形的水平边缘,然后垂直向上),间隔 + 线宽,从对角线(45º)长度转换为平行于要绘制的矩形的边缘。

    • 在每次迭代中,从该迭代的给定点到对边边缘上的点(45º)绘制一条线。我们通过简单地处理矩形的垂直边缘得到这一点,然后沿着水平)

    这样的事情应该可以达到预期的效果:

    class StripeyView : UIView {
    
        let lineGap: CGFloat = 7
        let lineWidth: CGFloat = 3
        let lineColor = UIColor.white
    
        override func draw(_ rect: CGRect) {
    
            let ctx = UIGraphicsGetCurrentContext()!
    
            // flip y-axis of context, so (0,0) is the bottom left of the context
            ctx.scaleBy(x: 1, y: -1)
            ctx.translateBy(x: 0, y: -bounds.size.height)
    
            // generate a slightly larger rect than the view,
            // to allow the lines to appear seamless
            let renderRect = bounds.insetBy(dx: -lineWidth * 0.5, dy: -lineWidth * 0.5)
    
            // the total distance to travel when looping (each line starts at a point that
            // starts at (0,0) and ends up at (width, height)).
            let totalDistance = renderRect.size.width + renderRect.size.height
    
            // loop through distances in the range 0 ... totalDistance
            for distance in stride(from: 0, through: totalDistance,
                                   // divide by cos(45º) to convert from diagonal length
                                   by: (lineGap + lineWidth) / cos(.pi / 4)) {
    
                // the start of one of the stripes
                ctx.move(to: CGPoint(
                    // x-coordinate based on whether the distance is less than the width of the
                    // rect (it should be fixed if it is above, and moving if it is below)
                    x: distance < renderRect.width ?
                        renderRect.origin.x + distance :
                        renderRect.origin.x + renderRect.width,
    
                    // y-coordinate based on whether the distance is less than the width of the
                    // rect (it should be moving if it is above, and fixed if below)
                    y: distance < renderRect.width ?
                        renderRect.origin.y :
                        distance - (renderRect.width - renderRect.origin.x)
                ))
    
                // the end of one of the stripes
                ctx.addLine(to: CGPoint(
                    // x-coordinate based on whether the distance is less than the height of
                    // the rect (it should be moving if it is above, and fixed if it is below)
                    x: distance < renderRect.height ?
                        renderRect.origin.x :
                        distance - (renderRect.height - renderRect.origin.y),
    
                    // y-coordinate based on whether the distance is less than the height of
                    // the rect (it should be fixed if it is above, and moving if it is below)
                    y: distance < renderRect.height ?
                        renderRect.origin.y + distance :
                        renderRect.origin.y + renderRect.height
                ))
            }
    
            // stroke all of the lines added
            ctx.setStrokeColor(lineColor.cgColor)
            ctx.setLineWidth(lineWidth)
            ctx.strokePath()
        }
    }
    

    输出:

    (假设视图有红色backgroundColor

    您可以调整lineGaplineWidth 属性以生成不同的结果。

    【讨论】:

    • 您有什么建议可以做出改变,以便能够以特定角度绘制线条吗?例如。 30 度而不是 45 度。
    【解决方案2】:

    惊人的简单算法...

    假设你有这些价值观:

        let T: CGFloat = 15     // desired thickness of lines
        let G: CGFloat = 30     // desired gap between lines
        let W = rect.size.width
        let H = rect.size.height
    

    值得注意的是,就是这么简单……

        var p = -(W > H ? W : H) - T
        while p <= W {
            
            c.move( to: CGPoint(x: p-T, y: -T) )
            c.addLine( to: CGPoint(x: p+T+H, y: T+H) )
            c.strokePath()
            p += G + T + T
        }
    

    这是一个完整的 UIView 类:

    class Ruled: UIView {
        
        override func draw(_ rect: CGRect) {
            
            let T: CGFloat = 15     // desired thickness of lines
            let G: CGFloat = 30     // desired gap between lines
            let W = rect.size.width
            let H = rect.size.height
            
            guard let c = UIGraphicsGetCurrentContext() else { return }
            c.setStrokeColor(UIColor.orange.cgColor)
            c.setLineWidth(T)
            
            var p = -(W > H ? W : H) - T
            while p <= W {
                
                c.move( to: CGPoint(x: p-T, y: -T) )
                c.addLine( to: CGPoint(x: p+T+H, y: T+H) )
                c.strokePath()
                p += G + T + T
            }
        }
    }
    

    就是这样!

    整个基本算法:

    1。从左上角开始,减去最长边

    2。画对角线直到你走到右边

    简单又好用! :)


    剪裁成矩形:

    上面的类只是简单地画了一个 UIView 大小的“盒子”。

    通常,您希望在一个视图中的不同位置绘制许多“框”。一个典型的例子是日历。

    此示例将绘制一个框。为您需要绘制的每个框调用它:

    此外,此示例显式绘制两条条纹,而不是在背景颜色上绘制一条条纹:

    func simpleStripes(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) {
         
        let stripeWidth: CGFloat = 20.0 // whatever you want
        let m = stripeWidth / 2.0
        
        guard let c = UIGraphicsGetCurrentContext() else { return }
        c.setLineWidth(stripeWidth)
        
        let r = CGRect(x: x, y: y, width: width, height: height)
        let longerSide = width > height ? width : height
        
        c.saveGState()
        c.clip(to: r)
            
            var p = x - longerSide
            while p <= x + width {
                
                c.setStrokeColor(pale blue)
                c.move( to: CGPoint(x: p-m, y: y-m) )
                c.addLine( to: CGPoint(x: p+m+height, y: y+m+height) )
                c.strokePath()
                
                p += stripeWidth
                
                c.setStrokeColor(pale gray)
                c.move( to: CGPoint(x: p-m, y: y-m) )
                c.addLine( to: CGPoint(x: p+m+height, y: y+m+height) )
                c.strokePath()
                
                p += stripeWidth
            }
            
        c.restoreGState()
    }
    

    如果你想让它们移动...

    1,要偏移,只需在启动时从指针中减去。令人惊讶的是,无需更改任何其他内容。

      var p = x - longerSide - offset // animate offset from 0 to stripeWidth
    

    2,细心的程序员更喜欢偏移等于斜接,以避免“尖尖的左上角”问题:

      var p = x - longerSide - offset - m // for better-looking top-left corner
    

    3,您可以使用任意数量的条纹各种颜色,实际上您可以使用不同的条纹宽度任意组合。令人惊讶的是,该算法仍然有效并且是安全的。 (如果你有多个宽度,只需将斜接m设置为最大宽度即可。)

    【讨论】:

    • 但是打开赏金并回答同样的问题@Fattie 有什么意义呢?
    • 对,带来更好的新答案!
    • @Fattie 如何使用 45º angel?
    【解决方案3】:

    最简单的画斜线代码:

    import UIKit
    
    @IBDesignable
    class SlashPatternView: UIView {
    @IBInspectable
    var lineWidth: CGFloat = 1 { didSet { setNeedsLayout() } }
    
    @IBInspectable
    var squareSize: CGFloat = 1 { didSet { setNeedsLayout() } }
    
    @IBInspectable
    var lineColor: UIColor = .white { didSet { setNeedsLayout() }}
    
    var slashes: UIImage {
        let size = squareSize
        let renderer = UIGraphicsImageRenderer(size: CGSize(width: size, height: size))
        return renderer.image { context in
            let cgcontext = context.cgContext
    
            cgcontext.addLines(between: [CGPoint(x: 0, y: size/2), CGPoint(x: size/2, y: 0)])
            cgcontext.addLines(between: [CGPoint(x: size/2, y: size), CGPoint(x: size, y: size/2)])
    
            cgcontext.setStrokeColor(lineColor.cgColor)
            cgcontext.setLineCap(.square)
            cgcontext.setLineWidth(lineWidth)
            cgcontext.strokePath()
        }
    }
    override func layoutSubviews() {
        super.layoutSubviews()
    }
    
    
    override func draw(_ rect: CGRect) {
        backgroundColor?.setFill()
        UIRectFill(rect)
        slashes.drawAsPattern(in: rect)
    }
    }
    

    【讨论】:

    • 等等——那不是只画两条线吗??
    猜你喜欢
    • 2021-05-04
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-28
    • 2021-06-04
    相关资源
    最近更新 更多