Как заполнить UIView
вот так (с некоторыми диагонально отрисованными белыми линиями).Заполнить UIView по диагонали линий?
PS: Мои намерения о заливке не на границе.
Любая помощь?
Как заполнить UIView
вот так (с некоторыми диагонально отрисованными белыми линиями).Заполнить UIView по диагонали линий?
PS: Мои намерения о заливке не на границе.
Любая помощь?
Одним из способов достижения этого было бы переопределить метод draw(_:)
UIView
и сделать свой собственный рисунок там.
Рисунок диагональных линий довольно прост, нужно просто:
Страйд от 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
для получения различных результатов.
Самый простой способ для меня - разместить фоновое изображение в вашем UIView (like this). Второе решение - рисовать линии с использованием Core Graphics Framework (более эффективное, но больше кода для записи).
Надеюсь, что эта помощь!
Скажите у вас есть эти значения ...
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
}
}
}
Всё!
Весь фундаментальный алгоритм:
легко и приятно! :)
Класс выше просто рисует его «размер 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
как максимальную ширину.)
Спасибо, и я очень ценю ваше объяснение больше, чем ваш ответ. – Goppinath
@ Goppinath рад помочь! :) – Hamish