我正在尝试为自己的练习制作一个简单的单一视图应用程序,但我遇到了一个问题,并且在过去的几天里没有解决这个问题 .
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")
}
并且在AppDelegate中调用上面类中的drawStyleOne函数 .
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
例程,它总是绘制相同的"style" .UIView
类在幕后工作做了很多 - 如果确保draw
不是't called unnecessarily, and schedules it when it is necessary, it figures out which parts of the view need re-drawn if they have been obscured (that'为什么它传递给你rect
),它为draw
设置了当前的图形上下文等等 .请参阅Ray Wenderlich教程或Apple docs . 正如Apple文档所说:
(我的重点)
所以你的代码应该是这样的:
我知道这不是你问题的答案,但你可以用另一种方式看待你的问题 . 您实际上不需要使用上下文或覆盖drawRect以便能够绘制线条 . 您可以直接使用图层 . 将它们添加到视图中,并在要更改样式并添加另一个样式时将其删除 . 你会像这样使用它:
然后在你appDelegate:
无论何时想要更改样式,都要更改变量myPhase,myLength和myColor,并在appDelegate中调用
yourView.setNeedsLayout()
. 这样你只需要一种方法来绘制所有样式 .