2017-02-02 26 views
2

Я пытаюсь создать простое приложение для одного вида для своей собственной практики, но у меня возникла проблема и не обошла эту проблему за последние пару дней.Перерисовывание CGContext после того, как оно уже нарисовано в Swift?

Screenshot of the current program

В принципе, когда я нажимаю любую из этих кнопок в стиле или настроить ползунок, я хочу, чтобы перерисовать CGContext, что это находится на нижней части экрана (красная пунктирная линия). Например, если нажать на кнопку ТИП 1, он должен вызвать функцию под названием drawStyleOne() и применить эти две различные изменения:

context?.setLineDash(phase: 0, lengths: [2,3]) 
context?.setStrokeColor(UIColor.green.cgColor) 

Моя цель состоит перерисовать пунктирная линия (меньше точек) и изменения цвет контекста - зеленый. (контекст - это экземпляр CGContext)

У меня есть все, нарисованное на переопределении func draw (_ rect: CGRect), но я не могу заставить его повторно рисовать CGContext так, как я этого хочу.

Вот часть моего кода, чтобы лучше объяснить эту ситуацию.

import UIKit 

class VectorView: UIView { 
private var context: CGContext? = nil 

override init(frame: CGRect) { 
    super.init(frame: frame) 
    //contentMode = .redraw //tried this, didn't work. 
} 

required init?(coder aDecoder: NSCoder) { 
    fatalError("init(coder:) has not been implemented") 
} 
override func draw(_ rect: CGRect) { 
    // lets us make calls 
    context = UIGraphicsGetCurrentContext()! 
    context?.move(to: CGPoint(x: 0.0, y: 10.0)) 
    context?.setLineDash(phase: 0, lengths: [2,3]) 
    context?.setLineJoin(CGLineJoin.bevel) 
    context?.setLineCap(CGLineCap.square) 

    context?.addLine(to: CGPoint(x: 50.0, y: 70.0)) 
    context?.addLine(to: CGPoint(x: 100.0, y: 20.0)) 

    context?.setLineWidth(1.0) 
    context?.setStrokeColor(UIColor.red.cgColor) 
    context?.drawPath(using: CGPathDrawingMode.stroke)   
} 

func drawStyleOne() { 

    context = UIGraphicsGetCurrentContext() 
    context?.move(to: CGPoint(x: 0.0, y: 10.0)) 
    context?.setLineDash(phase: 0, lengths: [2,3]) 
    context?.setLineJoin(CGLineJoin.bevel) 
    context?.setLineCap(CGLineCap.square) 

    context?.addLine(to: CGPoint(x: 50.0, y: 70.0)) 
    context?.addLine(to: CGPoint(x: 100.0, y: 20.0)) 

    context?.setStrokeColor(UIColor.green.cgColor) 

    context?.drawPath(using: CGPathDrawingMode.stroke) 
    self.setNeedsDisplay() 
    //contentMode = .redraw //Tried this and didn't work either.. 
    NSLog("drawStyleOne got called") 
} 

и функция drawStyleOne из класса выше вызывается внутри AppDelegate.

import UIKit 

@UIApplicationMain 
class AppDelegate: UIResponder, UIApplicationDelegate { 

    var window: UIWindow? 
    let screenSize = UIScreen.main.bounds 

    private var _vectorView: VectorView? = nil 
    private var _buttonStylesView: ButtonStyleView? = nil 

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 

     window = UIWindow() 
     window?.rootViewController = ViewController() 
     window?.rootViewController?.view.backgroundColor = UIColor.white 
     window?.makeKeyAndVisible() 

     _vectorView = VectorView() 
     _vectorView?.frame = CGRect(x: 0.0, y: 650, width: 414, height: 70) 
     _vectorView?.backgroundColor = UIColor.lightGray 
     window?.rootViewController?.view.addSubview(_vectorView!) 

     _buttonStylesView = ButtonStyleView() 
     _buttonStylesView?.frame = CGRect (x: screenSize.width/10, y: screenSize.height * 6/10, width: 414, height: 100) 
     _buttonStylesView?.backgroundColor = UIColor.clear 

     window?.rootViewController?.view.addSubview(_buttonStylesView!) 

     _buttonStylesView?.styleOne?.addTarget(self, action: #selector(styleButtonPressed), for: UIControlEvents.touchDown)  
     return true 
    } 

    func styleButtonPressed() { 
     NSLog("STYLE BUTTON PRESSED") 
     _vectorView?.drawStyleOne() 
    } 
} 

Я даже поставил NSLog («drawStyleOne получил колл») в конце просто чтобы убедиться, что функция получения называется (и это делает), однако он не будет перерисовывать линии независимо от того, что я стараюсь.

Любая помощь/совет были бы высоко оценены.

ответ

2

Вы должны сделать все вашего рисунка внутри override func draw(_ rect: CGRect) (или внутри подпрограмм, вызываемых оттуда). Таким образом, вашему draw нужен флаг, установленный снаружи (по вашим действиям), чтобы указать, какой из ваших стилей нужно сделать. Вы запускаете перерисовку с помощью setNeedsDisplay() - но это нужно вызывать из вашего действия, а не из кода рисования. Ваш текущий func drawStyleOne()пытается сделать, чтобы привлечь (но, вероятно, к недопустимому currentContext), а затем вызывает setNeedsDisplay(), который просто планирует вашу текущую рутину draw, которая всегда рисует тот же «стиль».

В UIView классе работает за кулисами, чтобы сделать довольно много - если убеждается, что draw не было напрасной, и графики, когда это необходимо, он выясняет, какие части зрения необходимости перерисованы, если они были закрыты (вот почему он передает вам rect), и он устанавливает, в частности, текущий графический контекст для draw.

См. Этот Ray Wenderlich учебник, или Apple docs. Как Apple, документы говорят:

Для пользовательских представлений, необходимо переопределить DrawRect: метод и выполнить все рисунок внутри него.

(курсив мой)

Так что ваш код должен выглядеть следующим образом:

class VectorView: UIView { 
    public var whichStyle: SomeEnumOfYours = // your default value 

    override func draw(_ rect: CGRect) { 
     switch self.whichStyle { 
     case .style1: 
      self.drawStyleOne() 
     case .style2: 
      self.drawStyleTwo() 
     //... 
     } 
    } 
} 

//... 
func styleButtonPressed() { 
    NSLog("STYLE BUTTON PRESSED") 
    _vectorView?.whichStyle = // whichever style required 
    _vectorView?.setNeedsDisplay() 
} 
+0

Большое спасибо за ваш ответ. Мне бы очень понравилось это голосовать, но сейчас у меня недостаточно очков репутации ... :( – whgnsdlr7

+0

@ whgnsdlr7 - вы все равно сможете принять его как правильный ответ (который сам по себе может дать вам достаточно rep, чтобы его проголосовать!) :) – Grimxn

0

Я знаю, что это не совсем ответ на ваш вопрос, но вы можете посмотреть на вашу проблему другим способом , Вам не нужно работать с контекстом или переопределять drawRect, чтобы иметь возможность рисовать линии. Вы можете работать непосредственно со слоями. Добавьте их в свое мнение и удалите их, когда вы хотите изменить стиль и добавить еще один. Вы бы использовать его как это:

import UIKit 

class VectorView: UIView { 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    var myColor = UIColor.red 
    var myPhase = 0 
    var myLength = [2,3] 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     guard let sublayers = self.layer.sublayers else { return } 
     // remove sublayer if any exists 
     for layer in sublayers { 
      layer.removeFromSuperlayer() 
     } 
     // draws your lines according to the style you have defined with your variables above 
     styledDrawing() 
    } 

    func styledDrawing() { 
     // creates a path and styles it 
     let path = UIBezierPath() 
     path.move(to: CGPoint(x: 0.0, y: 10.0)) 
     path.setLineDash(myLength, count: myLength.count, phase: myPhase) 
     path.lineJoinStyle = .bevel 
     path.lineCapStyle = .square 

     // add lines to the path 
     path.addLine(to: CGPoint(x: 50.0, y: 70.0)) 
     path.addLine(to: CGPoint(x: 100.0, y: 20.0)) 

     // creates a layer,adds your path to it and adds the layer to your view's layer 
     let layer = CAShapeLayer() 
     layer.path = path.cgPath 
     layer.lineWidth = 1.0 
     layer.strokeColor = myColor.cgColor 
     self.layer.addSublayer(layer) 
    } 
} 

Тогда в вас AppDelegate:

func styleButtonPressed() { 
    NSLog("STYLE BUTTON PRESSED") 
    _vectorView?.myColor = UIColor.green 
    _vectorView?.myLength = [4,1] 
    _vectorView?.setNeedsLayout() 
} 

Всякий раз, когда вы хотите изменить стиль, вы измените ваши переменные myPhase, myLength и myColor и вызвать yourView.setNeedsLayout() в AppDelegate. Таким образом, вам нужен только один метод для рисования всех ваших стилей.

+0

Я думаю, что это тоже будет работать нормально. Мне придется попробовать и это. Благодаря! – whgnsdlr7