[英]Access objects in ViewController from a different class in Swift
I have a ViewController with a UIView named myView
and a UIImageView named myImageView
. 我有一个ViewController,有一个名为myView
的UIView和一个名为myImageView
的UIImageView。 In the code below, I have a class named viewLine
which is attached to the UIView named myView
. 在下面的代码中,我有一个名为viewLine
的类,该类附加到名为myView
的UIView上。
The trouble I am having is when touchesEnded
is called, I want to change the alpha of myImageView
inside the ViewController. 我遇到的麻烦是调用touchesEnded
时,我想在ViewController中更改myImageView
的alpha。 When I try this, no changes to the the alpha of myImageView
occur. 当我尝试此操作时,不会更改myImageView
的alpha。
(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' .) (或者,当我尝试通过将viewLine
类移入主ViewController来实现此目标时,出现以下错误- override func drawRect(rect: CGRect)
- 方法不会覆盖其超类和self.setNeedsDisplay()
任何方法 - 值类型为“ ViewController”的成员没有成员“ 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
? 1-如何修改名为viewLine
的类中的代码以访问ViewController故事板上的其他UI对象或函数,例如myImageView
? ie How do I change the alpha of myImageView
from the class named viewLine
after touchesEnded
is called? 即在touchesEnded
被调用后, myImageView
从名为viewLine
的类中更改myImageView
的Alpha?
2 - I have a slider sliderLineSize
in the ViewController and a variable lineSize
in the ViewController. 2-我在ViewController中有一个sliderLineSize
滑块,在ViewController中有一个变量lineSize
。 The UISlider sliderLineSize
changes lineSize
. UISlider sliderLineSize
更改lineSize
。 However, lineSize
is used in the drawRect
section of the viewLine
class. 但是, lineSize
用于viewLine
类的drawRect
部分。 How do I pass or make accessible the variable set in the ViewController in the class? 如何传递或访问类中ViewController中设置的变量?
(3 - How do instead incorporate the viewLine
class into the main 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()
}
}
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? ) 我查找了有关如何从其子视图引用ViewController的信息,发现的最好的选择是StackOverflow回答说:“遵循MVC模式,ViewController知道其Views,但是View不应该知道ViewController。相反,您应该声明委托协议”(来源: Swift-如何将视图控制器的引用传递给子UIView类? )
So, I though the solution would be to write a custom delegate protocol and make the ViewController abide by it. 因此,我的解决方案是编写一个自定义委托协议,并使ViewController遵守该协议。 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. 前面提到的答案中的代码有些过时,无法编写委托协议,但是Pure Swift类中的问题的开头与使用静态方法的协议相符-向上转换的问题显示了如何正确编写可在我的Xcode 7.2中使用的协议。
My storyboard has a diagram like this: 我的情节提要有一个这样的图:
I renamed the class viewLine
to ViewLineUIView
as I thought it would be a more descriptive name of the underlying superclass. 我将ViewLineUIView
类重命名为viewLine
,因为我认为这将是基础超类的更具描述性的名称。 The code is below. 代码如下。
Code: 码:
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()
}
}
As you can see, editing the lineWidth of the path is straightforward and you don't need to create another delegate protocol. 如您所见,编辑路径的lineWidth很简单,您无需创建其他委托协议。 The ViewController can access its subviews directly. ViewController可以直接访问其子视图。 You should just be aware that a cast is needed. 您应该只知道需要强制转换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.