更改变量以查看实时更改Xcode Swift

问题描述 投票:-4回答:1

编辑

现在,我有了这个代码,它创建了一个spirograph的视图,然后在playground视图控制器中实例化它:

class Spirograph: UIView {

var insideRadius: CGFloat = 1 {
    didSet {
        updatePath()
    }
}
var rotationalSpeed: CGFloat = -31.0 / 3.0 {
    didSet {
        updatePath()
    }
}

private lazy var shapeLayer: CAShapeLayer = {
    let sl = CAShapeLayer()
    sl.fillColor = UIColor.clear.cgColor
    sl.strokeColor = UIColor.purple.cgColor
    sl.lineWidth = 2
    return sl
}()

override func layoutSubviews() {
    super.layoutSubviews()

    layer.addSublayer(shapeLayer)
    updatePath()
}

private func updatePath() {
    let path = UIBezierPath()
    let multiplier = frame.width / 5

    path.move(to: CGPoint(x: multiplier*(1+insideRadius) + bounds.midX, y: bounds.midY))

    for t in 0 ... 2000 {
        let angle = CGFloat(t) * .pi / 180.0
        let x = cos(angle) + insideRadius * cos(rotationalSpeed * angle)
        let y = sin(angle) + insideRadius * sin(rotationalSpeed * angle)

        path.addLine(to: CGPoint(x: multiplier * x + bounds.midX, y: multiplier * y + bounds.midY))
    }

    shapeLayer.path = path.cgPath

}

}

然后是实际观点:

class MyViewController : UIViewController {

let spirograph = Spirograph(frame: CGRect(x: 0, y: 0, width: 300, height: 300))

let slider = UISlider(frame: CGRect(x: 0, y: 300, width: 300, height: 20))

@objc func sliderMoved() {
    spirograph.insideRadius = CGFloat(slider.value)
}

override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = .blue
    spirograph.backgroundColor = .white

    slider.minimumValue = 0
    slider.maximumValue = 1
    slider.isContinuous = true
    slider.tintColor = .orange
    slider.addTarget(self, action: #selector(sliderMoved), for: .valueChanged)
    view.addSubview(slider)

    view.addSubview(spirograph)

}

}

每当我移动滑块时,即使是一点点,也需要15秒来映射新的肺活量计,可能是因为我没有在sliderMoved func中正确更改insideRadius变量

更新:我在xcode项目中运行相同的代码,它工作得很好,似乎操场无法处理这种类型的代码。

谢谢你的帮助!

swift xcode graph swift-playground uigraphicscontext
1个回答
0
投票

如果您希望在更改某些属性(例如insideRadiusrotationalSpeed)时更新视图,则通常会为该属性设置didSet观察器,以触发重新呈现路径。

现在,您的示例是构建图像。这是一种非常低效的方式(顺便说一下,所有透明图像都是不必要的)。我建议只使用CAShapeLayer。这样,您可以更新pathCAShapeLayer,操作系统将负责为您呈现它。

例如,您可能有一个UIView子类,它捕获您的路径创建内容并更新CAShapeLayer。各种didSet观察者将更新该形状图层的路径:

@IBDesignable
open class SpiralView: UIView {

    @IBInspectable open var insideRadius:    CGFloat = 1            { didSet { updatePath() }}
    @IBInspectable open var rotationalSpeed: CGFloat = -31.0 / 3.0  { didSet { updatePath() }}
    @IBInspectable open var strokeColor:     UIColor = .blue        { didSet { shapeLayer.strokeColor = strokeColor.cgColor }}
    @IBInspectable open var multiplier:      CGFloat = 100          { didSet { updatePath() }}
    @IBInspectable open var lineWidth:       CGFloat = 3            { didSet { shapeLayer.lineWidth = lineWidth }}

    private lazy var shapeLayer: CAShapeLayer = {
        let _shapeLayer = CAShapeLayer()
        _shapeLayer.fillColor = UIColor.clear.cgColor
        _shapeLayer.strokeColor = strokeColor.cgColor
        _shapeLayer.lineWidth = lineWidth
        return _shapeLayer
    }()

    override open func layoutSubviews() {
        super.layoutSubviews()

        layer.addSublayer(shapeLayer)

        updatePath()
    }

    private func updatePath() {
        let path = UIBezierPath()

        path.move(to: CGPoint(x: multiplier*(1+insideRadius) + bounds.midX, y: bounds.midY))

        for t in 0 ... 2000 {
            let angle = CGFloat(t) * .pi / 180.0
            let x = cos(angle) + insideRadius * cos(rotationalSpeed * angle)
            let y = sin(angle) + insideRadius * sin(rotationalSpeed * angle)

            path.addLine(to: CGPoint(x: multiplier * x + bounds.midX, y: multiplier * y + bounds.midY))
        }

        shapeLayer.path = path.cgPath
    }
}

现在,您可以根据需要将此视图添加到UI中(例如,您的游乐场视图控制器可能会以编程方式将其添加为其主要view的子视图;如果在iOS项目中,您可以将其添加到故事板中)。但是现在,当您更新任何这些属性时,将为您重新呈现视图。

顺便说一下,如果你在带有故事板的iOS项目中使用它,那只需要@IBDesignable@IBInspectable。这只是一个很好的功能,可以让你在IB中看到正好呈现的螺旋线,你可以在故事板中调整这些变量并动态反映它。但如果你在操场上这样做,那些关键字就没有必要了。但是,坦率地说,我发现游乐场太慢而不适合这样的事情。


然后,您可以将其连接到滑块,例如

class ViewController: UIViewController {

    @IBOutlet weak var slider: UISlider!
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var spiralView: SpiralView!

    override func viewDidLoad() {
        super.viewDidLoad()

        slider.value = Float(spiralView.insideRadius)
        slider.addTarget(self, action: #selector(valueDidChange(_:)), for: .valueChanged)
    }

    @objc func valueDidChange(_ sender: Any) {
        label.text = "\(slider.value)"
        spiralView.insideRadius = CGFloat(slider.value)
    }
}

导致:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.