ios - 从 Swift 中的不同类访问 ViewController 中的对象

标签 ios swift class uiview uiviewcontroller

我有一个 ViewController,它有一个名为 myView 的 UIView 和一个名为 myImageView 的 UIImageView。在下面的代码中,我有一个名为 viewLine 的类,它附加到名为 myView 的 UIView。

我遇到的问题是当 touchesEnded 被调用时,我想更改 ViewController 中 myImageView 的 alpha。当我尝试这样做时,myImageView 的 alpha 没有发生任何变化。

(或者,当我尝试通过将 viewLine 类移动到主 ViewController 中来实现此目的时,会出现以下错误 - override func drawRect(rect: CGRect) - 方法不会覆盖其父类(super class)中的任何方法self.setNeedsDisplay() - “ViewController”类型的值没有成员“setNeedsDisplay”。 )

问题:

1 - 如何修改名为 viewLine 的类中的代码以访问 ViewController Storyboard上的其他 UI 对象或函数,例如 myImageView?即,如何在调用 touchesEnded 后从名为 viewLine 的类更改 myImageView 的 alpha?

2 - 我在 ViewController 中有一个 slider sliderLineSize,在 ViewController 中有一个变量 lineSize。 UISlider sliderLineSize 更改 lineSize。但是,lineSize 用于 viewLine 类的 drawRect 部分。 如何传递或访问类中 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()
    }

}

最佳答案

我查阅了有关如何从其 subview 引用 ViewController 的信息,我发现最好的选择是 StackOverflow 的回答,它说“遵循 MVC 模式,ViewController 知道它的 View ,但 View 不应该知道 ViewController。相反,您应该声明委托(delegate)协议(protocol)”(来源:Swift - How to pass a view controller's reference to a sub UIView class?)

因此,我认为解决方案是编写自定义委托(delegate)协议(protocol)并让 ViewController 遵守它。上述答案中的代码编写委托(delegate)协议(protocol)有点过时,但问题的开头在 Pure Swift class conforming to protocol with static method - issue with upcasting展示了如何正确编写适用于我的 Xcode 7.2 的协议(protocol)。

我的 Storyboard有一个这样的图表:

  • 查看
    • 我的 View (链接到您的代码)
    • 我的 ImageView (背景是我选择的静态图像)

我将类 viewLine 重命名为 ViewLineUIView,因为我认为这将是底层父类(super class)的更具描述性的名称。代码如下。

代码:

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 非常简单,您不需要创建另一个委托(delegate)协议(protocol)。 ViewController 可以直接访问它的 subview 。您应该只知道需要强制转换。

关于ios - 从 Swift 中的不同类访问 ViewController 中的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35319995/

相关文章:

ios - 如何在 iOS 中更新或编辑 EKEvent 并使用标识符存储在 native 日历中?

ios - quickblox中在线离线用户状态

ios - 使 UIButton 在 UILabel 之后换行

ios - 我如何继续使用 Swift 2.3 而不是 3.0,Xcode 已更新且无法再构建

c++ - 使用函数指针在类之间传递数据

c# - 类中的方法可以接收与参数相同的类吗?

ios - 使用 LAContext 和 touchIDAuthenticationAllowableReuseDuration 获取钥匙串(keychain)项目

ios - Swift,从异步 block 返回值

ios - 如何使 UILabel 出现和消失 5 次?

C# 奇怪的对象行为