2017-02-02 6 views
2

나는 내 자신의 연습을 위해 간단한 단일보기 응용 프로그램을 만들려고 노력하고 있지만 문제가 발생하여 지난 며칠 동안이 문제를 해결하지 못했습니다. 나는이 스타일의 버튼 중 하나를 누르거나 슬라이더를 조정하면 Swift에서 이미 그려진 CGContext를 다시 그립니다.

Screenshot of the current program

기본적으로, 나는 그것이 화면 (빨간 점선)의 하단에 년대 CGContext를 다시 그려야합니다. 나는 STYLE 1 버튼을 누르면 예를 들어,이 drawStyleOne (호출 한 함수)를 호출하고이 두 개의 서로 다른 변경 적용해야합니다 :

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

내 목표는 다시 그리는 점선 (작은 점)에 있고 변화를 컨텍스트의 색은 녹색 (컨텍스트는 CGContext의 인스턴스입니다.)

모든 것은 override 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() 
    } 
} 

, 그러나 그것은 아무리 내가 무엇을하려고 줄을 다시 그리기하지 않습니다 난 그냥 함수가 호출지고 있는지 확인하기 위해 마지막에 ("drawStyleOne 호출있어") NSLog를 넣어 (그리고는 않습니다).

도움/조언을 많이 주시면 감사하겠습니다.

답변

2

모두 (내선 번호 override func draw(_ rect: CGRect)) 내부에 도면을 작성해야합니다. 따라서 귀하의 draw은 (귀하의 행동에 의해) 그려야 할 스타일을 알려주는 플래그가 필요합니다. setNeedsDisplay()을 사용하여 다시 그리기를 트리거하지만 그리기 코드가 아닌 작업에서 호출해야합니다. 귀하의 현재 func drawStyleOne() (아마도 잘못된 currentContext)을 그리기를 시도한 다음 setNeedsDisplay()을 호출합니다. 실제 draw 루틴이 실행되도록 예약합니다.이 루틴은 항상 동일한 "스타일"을 그리게됩니다.

UIView 클래스는 무의식적으로 호출되지 않고 draw이 불필요하게 호출되지 않도록하고 필요한 경우 일정을 계획하면보기의 어느 부분이 다시 그리기가 필요한지 파악합니다 (그것이 당신에게 rect을 전달하는 이유입니다) 그리고 다른 것들 중에서도 draw에 대한 현재 그래픽 컨텍스트를 설정합니다.

Ray Wenderlich 튜토리얼 또는 Apple docs을 참조하십시오. 애플 문서가 말하는 것처럼 : 방법과 그 안에 모든 드로잉을 수행 : 사용자 정의보기를 들어

, 당신은의 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 - 정답으로 받아 들일 수 있어야한다. 투표를하기 위해 담당자에게!) :) – 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을 변경하고 AppDelegate에에 yourView.setNeedsLayout()를 호출합니다. 그렇게하면 모든 스타일을 그리는 데 필요한 한 가지 방법 만 있으면됩니다.

+0

나는 이것이 또한 잘 동작 할 것이라고 생각한다. 나는 이것을 밖으로 시도해야 할 것이다. 감사! – whgnsdlr7