2016-11-30 3 views
3

У меня странная проблема с UIBezierPath, где мой цвет и ширина линии не отображаются правильно.Неверный цвет и ширина линии с UIBezierPath

Я рисую серию линий (например, линейку) с основными и второстепенными градациями. Основные градации линии с большей длиной ...

Основные Градация: Цвет Красный & Ширина линии: 2,0 Minor Градация: Цвет Желтый & Ширина линии: 0,0 (тонкая линия в соответствии со спецификацией)

slider

override func draw(in ctx: CGContext) { 
    if let _ = cameraControlSlider { 
     guard gradationValues.count >= 0 else { 
      return 
     } 

     let frame = CGRect(x: insetBy, y: 0, width: bounds.width - insetBy, height: bounds.height) 
     ctx.clear(frame) 

     let startx = Int(frame.origin.x) 
     let endx = Int(frame.origin.x + frame.width) 

     let incrementWidth = (endx - startx)/(gradationValuesOnScreen + 1) 

     var counter = 1 
     var x = startx + counter * incrementWidth 

     while x < endx { 

      var y1 = Int(frame.origin.y) 
      var y2 = Int(frame.origin.y) + Int(frame.height) 
      var lineWidth: Float = 2.0 
      var color = UIColor.red 

      if counter % majorGradationInterval != 1 { 
       y1 = Int(frame.origin.y) + Int(frame.height/4) 
       y2 = Int(frame.origin.y + frame.height) - Int(frame.height/4) 
       lineWidth = 0.0 
       color = UIColor.yellow 
      } 

      ctx.addPath(drawLine(in: ctx, x1: x, y1: y1, x2: x, y2: y2, color: color, lineWidth: lineWidth)) 
      counter += 1 
      x = startx + counter * incrementWidth 
     } 
    } 
} 

func drawLine(in ctx: CGContext, x1: Int, y1: Int, x2: Int, y2: Int, color: UIColor, lineWidth: Float) -> CGPath { 
    let path = UIBezierPath() 

    ctx.setStrokeColor(color.cgColor) 

    path.lineWidth = CGFloat(lineWidth) 
    path.move(to: CGPoint(x: x1, y: y1)) 
    path.addLine(to: CGPoint(x: x2, y: y2)) 
    path.close() 

    ctx.strokePath() 

    return path.cgPath 
} 

По существу, я хочу, чтобы более длинные линии имели цвет RED и толщину линий, но цвета выглядели инвертированными, и ширина линии, по-видимому, не оказывала никакого влияния.

Как видно из функции рисования, отсутствует красный UIColor, который связан с меньшей длиной линии. Я попытался установить цвет удара до создания пути, но это, похоже, не работает.

ответ

2

Здесь есть пара вопросов, но ключевая проблема заключается в том, что drawLine создает UIBezierPath и звонит strokePath. Но strokePath не обрабатывает то, что UIBezierPath вы только что создали, а скорее предыдущий путь, добавленный в этот контекст. Но так как вы не добавляете строку в контекст до тех пор, пока не вернетесь с drawLine, все будет отключено на единицу. Кроме того, поскольку вы добавляете все эти строки в контекст (вместо замены пути), вы повторяете повторную перерисовку строк.

Вы можете это исправить, просто вызывая drawLine, а не addPath(drawLine(...):

override func draw(in ctx: CGContext) { 
    ... 

    while x < endx { 
     ... 

     drawLine(in: ctx, x1: x, y1: y1, x2: x, y2: y2, color: color, lineWidth: lineWidth) 

     ... 
    } 
} 

И drawLine не возвращает ничего, но на самом деле просто тянет его:

func drawLine(in ctx: CGContext, x1: Int, y1: Int, x2: Int, y2: Int, color: UIColor, lineWidth: Float) { 
    let path = UIBezierPath() 

    ctx.saveGState() 
    ctx.setStrokeColor(color.cgColor) 
    ctx.setLineWidth(CGFloat(lineWidth)) 
    path.move(to: CGPoint(x: x1, y: y1)) 
    path.addLine(to: CGPoint(x: x2, y: y2)) 
    ctx.addPath(path.cgPath) 
    ctx.strokePath() 
    ctx.restoreGState() 
} 

Обратите внимание, я экономлю и восстановление графического контекста, чтобы каждый раз рисовать новый сегмент линии линии. Кроме того, поскольку я поглаживаю путь контекста, я вызываю setLineWidth в контексте, а не в путь. Кроме того, здесь не показано, я обнаружил, что если я гладил желтые линии с шириной нуля, они не появлялись, так что я использовал 1:

example image

Примечание, если бы это было UIView подкласс вы может упростить это дальнейшее (просто погладьте UIBezierPath, а не вмешивайтесь в CoreGraphics, вы можете сделать это @IBDesignable и т. д.). Но если вы собираетесь реализовать draw(in:), я, вероятно, сделаю что-то вроде выше.

+0

Это было идеально @Rob. Это имеет смысл. Однако вы упомянули, что он перерисовывается с момента добавления в контекст. Разве это не произойдет с изменениями, упомянутыми выше, а также с сохранением состояния G. Кроме того, когда вы используете path.stroke vs ctx.stroke. Path.stroke давал мне ошибки с недопустимым контекстом, поэтому я не использовал его. Подход UIView звучит интересно. Я должен попробовать. Большое спасибо. – ssarangi

+0

Повторно перерисовывая, потому что мы сохраняем и восстанавливаем контекст, путь возвращается в прежнее состояние без указания пути (например, сохраняет контекст, добавляет путь, обводят его и восстанавливает в состояние без пути и повторяет). – Rob

+0

Re 'path.stroke', вы используете это, когда вы уже находитесь в графическом контексте (например,в 'draw (_ rect:)' подкласса 'UIView'). Мне очень нравится подкласс подкласса «UIView», потому что код проще, вы можете просто добавить его в иерархию представлений, как и любой другой «UIView», и, если это необходимо, сделать его «@ IBDesignable» и увидеть его прямо в ваш раскадровки. Но у вас может быть достаточно написано вокруг шаблона 'draw (in:)', который больше работает, чем нужно. К счастью, оба подхода работают нормально. – Rob

Смежные вопросы