用对角线绘制的 UIView 填充?
Fill a UIView with diagonally drawn lines?
如何像这样填充 UIView
(用一些对角线绘制的白线)。
PS:我的意图是关于填充而不是边框。
有什么帮助吗?
实现此目的的一种方法是覆盖 UIView
的 draw(_:)
方法并在那里进行自定义绘制。
绘制对角线非常简单,您只需要:
从0到宽度+高度(沿着矩形的水平边缘,然后向上垂直),通过间隙+线宽,从对角线(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
)
您可以调整 lineGap
和 lineWidth
属性来生成不同的结果。
非常简单的算法...
假设您有这些值:
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:
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。画对角线直到你来到右边
简单又好用! :)
要剪辑到矩形:
上面的 class 只是绘制了一个 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
设置为最大宽度即可。)
画斜线最简单的代码:
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)
}
}
如何像这样填充 UIView
(用一些对角线绘制的白线)。
PS:我的意图是关于填充而不是边框。
有什么帮助吗?
实现此目的的一种方法是覆盖 UIView
的 draw(_:)
方法并在那里进行自定义绘制。
绘制对角线非常简单,您只需要:
从0到宽度+高度(沿着矩形的水平边缘,然后向上垂直),通过间隙+线宽,从对角线(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
)
您可以调整 lineGap
和 lineWidth
属性来生成不同的结果。
非常简单的算法...
假设您有这些值:
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:
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。画对角线直到你来到右边
简单又好用! :)
要剪辑到矩形:
上面的 class 只是绘制了一个 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
设置为最大宽度即可。)
画斜线最简单的代码:
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)
}
}