如何从另一个 UIView 访问 UIControl 的值 class

How to access the value of a UIControl from another UIView class

初学者问题。我在故事板上有一个 UISlider,在另一个 UIView class 除了 ViewController 之外,我想使用滑块的值来更改 makeShape() 函数中的 path/shape 变量。

我试过:

a) 在OtherView中,尝试直接引用ViewController的全局变量val。这导致 "unresolved identifier"

b) 在 ViewController 中,尝试将 mySlider.value 赋值给在 OtherView otherVal 中声明的变量。这导致 "Instance member 'otherVal' cannot be used on type 'OtherView'".

有人可以帮助我了解如何正确执行此操作吗?

ViewController.swift:

class ViewController: UIViewController {

    var val: CGFloat = 0.0

    @IBOutlet weak var mySlider: UISlider!

    @IBOutlet weak var otherView: UIView!

    @IBAction func mySliderChanged(_ sender: Any) {
        val = CGFloat(mySlider.value)
        setOtherVal()
    }

    func setOtherVal() {
        otherView.otherVal = val
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let otherView = OtherView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 100, height: 100)))

        self.view.addSubview(otherView)
    }
}

OtherView.swift:

class OtherView: UIView {

    var path: UIBezierPath!

    var otherVal: CGFloat = 0.0

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.clear
        makeShape()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func makeShape() {
        let width: CGFloat = self.frame.size.width
        let height: CGFloat = self.frame.size.height

        let path1 = UIBezierPath(ovalIn: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 50, height: 50)))

        let shapeLayer1 = CAShapeLayer()
        shapeLayer1.path = path1.cgPath
        shapeLayer1.fillColor = UIColor.blue.cgColor

        self.layer.addSublayer(shapeLayer1)

        shapeLayer1.position = CGPoint(x: otherVal, y: height)
    }
}

现在您正在尝试访问 class OtherVal 上的 ViewController 中的 otherVal 属性,该 otherVal 属性 通过整个应用程序在全球范围内共享,而不是您在 ViewController 中创建的 OtherVal 实例上的 属性。

此处最简单的解决方法是存储您在 viewDidAppear 中创建的 OtherView 实例并使用该 属性 更新视图。

class ViewController: UIViewController {

    var val: Float = 0.0
    @IBOutlet weak var mySlider: UISlider!

    // Add a property to hold on to the view after you create it. 
    var otherView: OtherView?

    @IBAction func mySliderChanged(_ sender: Any) {
        val = mySlider.value
        setOtherVal()
    }

    func setOtherVal() {
        // `val` is a Float and `otherVal` is a `CGFloat` so we have to convert first.
        let newValue = CGFloat(self.val)
        // Use the property that's holding your view to update with the new value from the slider.
        self.otherView?.otherVal = newValue
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let otherView = OtherView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 100, height: 100)))

        // Set the property to the view you just created so you can update it later.
        self.otherView = otherView

        self.view.addSubview(otherView)
    }
}

目前虽然看起来您并没有真正更新 OtherView 一旦设置了新值,所以您会想在那里做类似的事情。保留对您创建的 CAShapeLayer 的引用,并在 otherVal 更改时更新位置。

另请注意 viewDidAppear 可以在视图控制器的整个生命周期中多次调用。如果你只想添加一次视图,你应该使用 viewDidLoad 这将保证你有一个新创建的 self.view 可以使用。

编辑:如评论中所述,您还可以在情节提要/笔尖中设置自定义视图并创建插座。不过,现在看起来您的代码并未设置为使用它。