2016-03-02 2 views

ответ

11

Одним из способов достижения этого было бы переопределить метод 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() 
    } 
} 

Выход:

enter image description here

(Предполагая, что у вида есть красный backgroundColor)

Вы можете настроить свойства lineGap и lineWidth для получения различных результатов.

+0

Спасибо, и я очень ценю ваше объяснение больше, чем ваш ответ. – Goppinath

+0

@ Goppinath рад помочь! :) – Hamish

-3

Самый простой способ для меня - разместить фоновое изображение в вашем UIView (like this). Второе решение - рисовать линии с использованием Core Graphics Framework (более эффективное, но больше кода для записи).

Надеюсь, что эта помощь!

7

Удивительно простой алгоритм ...

Скажите у вас есть эти значения ...

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 
    } 

enter image description here

Здесь является полным классом 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». Часто вы хотите нарисовать несколько «ящиков» на самом деле в пределах представления в разных координатах. (Хороший пример для календаря).

enter image description here

Кроме того, в этом примере явно черпает «обе полосы», а не рисовать одну полосу за цвет фона:

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 

enter image description here

3, Вы можете использовать любое количество полос в различных цветах, и действительно вы можете использовать различные ширины полос в любой комбинации. Удивительно, что алгоритм все еще работает и безопасен. (Если у вас более одной ширины, просто установите митру m как максимальную ширину.)

+0

еще раз спасибо, и это очень приятно объяснить примерами. Еще раз спасибо! – Goppinath

+0

наслаждайтесь, @Goppinath! – Fattie

+0

Но в чем смысл открытия щедрости и ответа на тот же вопрос @Fattie? – Goppinath