I have a ViewController with a UIView named myView
and a UIImageView named myImageView
. In the code below, I have a class named viewLine
which is attached to the UIView named myView
.
The trouble I am having is when touchesEnded
is called, I want to change the alpha of myImageView
inside the ViewController. When I try this, no changes to the the alpha of myImageView
occur.
(Alternatively, when I try to achieve this by moving the viewLine
class into the main ViewController, the following errors present - override func drawRect(rect: CGRect)
- Method does not override any method from its superclass and self.setNeedsDisplay()
- Value of type 'ViewController' has no member 'setNeedsDisplay’.)
Questions:
1 - How do I modify the code in the class named viewLine
to access other UI objects or functions on the ViewController storyboard such as myImageView
? i.e. How do I change the alpha of myImageView
from the class named viewLine
after touchesEnded
is called?
2 - I have a slider sliderLineSize
in the ViewController and a variable lineSize
in the ViewController. The UISlider sliderLineSize
changes lineSize
. However, lineSize
is used in the drawRect
section of the viewLine
class.
How do I pass or make accessible the variable set in the ViewController in the class?
(3 - How do instead incorporate the viewLine
class into the main 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()
}
}
I looked up about how to reference a ViewController from its subview and the best bet I found was a StackOverflow answer saying "Following the MVC pattern, a ViewController knows about its Views, but the View shouldn't know about the ViewController. Instead you should declare delegate protocol" (Source: Swift - How to pass a view controller's reference to a sub UIView class?)
So, I though the solution would be to write a custom delegate protocol and make the ViewController abide by it. The code in the aforementioned answer is a bit outdated to write the delegate protocol, but the beginning of the question in Pure Swift class conforming to protocol with static method - issue with upcasting shows how to write a protocol properly that works in my Xcode 7.2.
My storyboard has a diagram like this:
I renamed the class
viewLine
toViewLineUIView
as I thought it would be a more descriptive name of the underlying superclass. The code is below.Code:
As you can see, editing the lineWidth of the path is straightforward and you don't need to create another delegate protocol. The ViewController can access its subviews directly. You should just be aware that a cast is needed.