我有一个ViewController,其中包含名为myView
的UIView和名为myImageView
的UIImageView。在下面的代码中,我有一个名为viewLine
的类,它附加到名为myView
的UIView。
我遇到的麻烦是调用touchesEnded
时,我想在ViewController中更改myImageView
的alpha。当我尝试这个时,myImageView
的alpha值没有变化。
(或者,当我尝试通过将viewLine
类移动到主ViewController中来实现此目的时,会出现以下错误 - override func drawRect(rect: CGRect)
- Method不会覆盖其超类中的任何方法< / em>和self.setNeedsDisplay()
- “ViewController”类型的值没有成员'setNeedsDisplay'。)
问题:
1 - 如何修改名为viewLine
的类中的代码以访问ViewController故事板上的其他UI对象或函数,例如myImageView
?即,在myImageView
被调用后,如何更改viewLine
类中touchesEnded
的alpha?
2 - 我在ViewController中有一个滑块sliderLineSize
,在ViewController中有一个变量lineSize
。 UISlider sliderLineSize
更改lineSize
。但是,lineSize
类的drawRect
部分使用了viewLine
。
如何传递或访问类中ViewController中的变量集?
(3 - 如何将viewLine
类合并到主ViewController中?)
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myView: UIView!
@IBOutlet weak var myImageView: UIImageView!
var lineSize: Int = 1
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
myImageView.alpha = 0.5
}
@IBAction func sliderLineSize(sender: UISlider) {
lineSize = Int(sender.value)
}
}
class viewLine: UIView {
let path=UIBezierPath()
var incrementalImage:UIImage?
var previousPoint:CGPoint = CGPoint.zero
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
incrementalImage?.drawInRect(rect)
path.lineWidth = lineSize
path.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
path.moveToPoint(currentPoint)
previousPoint=currentPoint
self.setNeedsDisplay()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
let midPoint = self.midPoint(previousPoint, p1: currentPoint)
path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
previousPoint=currentPoint
path.moveToPoint(midPoint)
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.drawBitmap()
self.setNeedsDisplay()
path.removeAllPoints()
}
func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint {
let x=(p0.x+p1.x)/2
let y=(p0.y+p1.y)/2
return CGPoint(x: x, y: y)
}
func drawBitmap() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 1)
strokeColor?.setStroke()
if((incrementalImage) == nil){
let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
UIColor.whiteColor().setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
答案 0 :(得分:2)
我查看了如何从其子视图引用ViewController,我发现最好的赌注是StackOverflow回答说&#34;遵循MVC模式,ViewController知道它的视图,但视图不应该是了解ViewController。相反,你应该声明委托协议&#34; (来源:Swift - How to pass a view controller's reference to a sub UIView class?)
所以,我的解决方案是编写自定义委托协议并使ViewController遵守它。上述答案中的代码有点过时,无法编写委托协议,但Pure Swift class conforming to protocol with static method - issue with upcasting中问题的开头显示了如何正确编写适用于我的Xcode 7.2的协议。
我的故事板上有这样的图表:
我将类viewLine
重命名为ViewLineUIView
,因为我认为它将是底层超类的更具描述性的名称。代码如下。
代码:
import UIKit
protocol ViewLineUIViewDelegate: class {
func onTouchesEnded(viewLine: ViewLineUIView)
}
class ViewController: UIViewController, ViewLineUIViewDelegate {
@IBOutlet weak var myView: UIView!
@IBOutlet weak var myImageView: UIImageView!
@IBOutlet weak var sliderValue: UISlider!
var viewLineDelegate: ViewLineUIView!
override func viewDidLoad() {
super.viewDidLoad()
viewLineDelegate = myView as? ViewLineUIView
viewLineDelegate!.delegate = self
//update lineWidth to initial value of slider
updateLineWidth()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func onTouchesEnded(viewLine: ViewLineUIView) {
myImageView!.alpha = 0.5
}
//Updating lineWidth!
@IBAction func onSliderChange(sender: UISlider) {
updateLineWidth()
}
func updateLineWidth() {
let drawView = myView as! ViewLineUIView
//you can change this "10" value to your max lineWidth
drawView.path.lineWidth = CGFloat(sliderValue.value*10)
print("New value is: " + String(drawView.path.lineWidth))
}
}
class ViewLineUIView: UIView {
weak var delegate: ViewLineUIViewDelegate?
let path=UIBezierPath()
var incrementalImage:UIImage?
var previousPoint:CGPoint = CGPoint.zero
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
//Initialize lineWidth so that compiler doesn't complain
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
incrementalImage?.drawInRect(rect)
path.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
path.moveToPoint(currentPoint)
previousPoint=currentPoint
self.setNeedsDisplay()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
let midPoint = self.midPoint(previousPoint, p1: currentPoint)
path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
previousPoint=currentPoint
path.moveToPoint(midPoint)
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.drawBitmap()
self.setNeedsDisplay()
path.removeAllPoints()
delegate?.onTouchesEnded(self)
}
func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint {
let x=(p0.x+p1.x)/2
let y=(p0.y+p1.y)/2
return CGPoint(x: x, y: y)
}
func drawBitmap() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 1)
strokeColor?.setStroke()
if((incrementalImage) == nil){
let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
UIColor.whiteColor().setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
如您所见,编辑路径的lineWidth非常简单,您不需要创建另一个委托协议。 ViewController可以直接访问其子视图。你应该知道需要演员。