简体   繁体   English

从Swift中的另一个类访问ViewController中的对象

[英]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: 我的情节提要有一个这样的图:

  • View 视图
    • My View (linked to your code) 我的视图(链接到您的代码)
    • My Image View (background is a static image I chose) 我的图像视图(背景是我选择的静态图像)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM