首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从标准视图构建自定义视图的操作问题

从标准视图构建自定义视图的操作问题
EN

Stack Overflow用户
提问于 2018-06-20 12:30:43
回答 1查看 78关注 0票数 1

我有一个自定义视图子类NSView,它只是一个包含标签、滑块、第二个标签和复选框的NSStackView。滑块和复选框都配置为报告对视图的更改(并最终通过ViewController的委托):

代码语言:javascript
复制
fileprivate extension NSTextField {
    static func label(text: String? = nil) -> NSTextField {
        let label = NSTextField()
        label.isEditable = false
        label.isSelectable = false
        label.isBezeled = false
        label.drawsBackground = false
        label.stringValue = text ?? ""
        return label
    }
}

@IBDesignable
class Adjustable: NSView {

    private let sliderLabel = NSTextField.label()
    private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
    private let valueLabel = NSTextField.label()
    private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))

    var valueFormatter: (Double)->(String) = { String(format:"%5.2f", $0) }

    ...

    @objc func sliderChanged(_ sender: Any) {
        guard let slider = sender as? NSSlider else { return }

        valueLabel.stringValue = valueFormatter(slider.doubleValue)
        print("Slider now: \(slider.doubleValue)")

        delegate?.adjustable(self, changedValue: slider.doubleValue)
    }

    @objc func enabledChanged(_ sender: Any) {
        guard let checkbox = sender as? NSButton else { return }
        print("Enabled now: \(checkbox.state == .on)")

        delegate?.adjustable(self, changedEnabled: checkbox.state == .on)
    }
}

使用InterfaceBuilder,我可以通过拖动一个CustomView并在标识检查器中设置它的类,将其一个实例添加到ViewController中。切换复选框或更改滑块将产生预期效果。

但是,如果我有多个实例,那么在目标操作函数中,self总是引用视图的同一个实例,而不是与之交互的实例。换句话说,self.slider == sender只适用于其中一个滑块的sliderChanged。虽然我可以通过sender获得正确的滑块值,但是我不能更新正确的标签,因为self.valueLabel总是自定义视图的第一个实例中的标签。

顺便说一句,@IBDesignable和支持它的代码没有任何效果,所以我也缺少一些东西-- Interface只是显示空空间。

整个档案:

代码语言:javascript
复制
import Cocoa

fileprivate extension NSTextField {
    static func label(text: String? = nil) -> NSTextField {
        let label = NSTextField()
        label.isEditable = false
        label.isSelectable = false
        label.isBezeled = false
        label.drawsBackground = false
        label.stringValue = text ?? ""
        return label
    }
}

protocol AdjustableDelegate {
    func adjustable(_ adjustable: Adjustable, changedEnabled: Bool)
    func adjustable(_ adjustable: Adjustable, changedValue: Double)
}

@IBDesignable
class Adjustable: NSView {
    var delegate: AdjustableDelegate? = nil

    private let sliderLabel = NSTextField.label()
    private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
    private let valueLabel = NSTextField.label()
    private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))

    var valueFormatter: (Double)->(String) = { String(format:"%5.2f", $0) }

    @IBInspectable
    var label: String = "" {
        didSet {
            sliderLabel.stringValue = label
        }
    }

    @IBInspectable
    var value: Double = 0 {
        didSet {
            slider.doubleValue = value
            valueLabel.stringValue = valueFormatter(value)
        }
    }

    @IBInspectable
    var enabled: Bool = false {
        didSet {
            enabledCheckbox.isEnabled = enabled
        }
    }

    @IBInspectable
    var minimum: Double = 0 {
        didSet {
            slider.minValue = minimum
        }
    }

    @IBInspectable
    var maximum: Double = 100 {
        didSet {
            slider.maxValue = maximum
        }
    }

    @IBInspectable
    var tickMarks: Int = 0


    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

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

    override func prepareForInterfaceBuilder() {
        setup()
    }

    override func awakeFromNib() {
        setup()
    }

    private func setup() {
        let stack = NSStackView()
        stack.orientation = .horizontal
        stack.translatesAutoresizingMaskIntoConstraints = false

        stack.addArrangedSubview(sliderLabel)
        stack.addArrangedSubview(slider)
        stack.addArrangedSubview(valueLabel)
        stack.addArrangedSubview(enabledCheckbox)

        sliderLabel.stringValue = label
        slider.doubleValue = value
        valueLabel.stringValue = valueFormatter(value)
        slider.minValue = minimum
        slider.maxValue = maximum
        slider.numberOfTickMarks = tickMarks

        // Make the slider be the one that expands to fill available space
        slider.setContentHuggingPriority(NSLayoutConstraint.Priority(rawValue: 249), for: .horizontal)

        sliderLabel.widthAnchor.constraint(equalToConstant: 60).isActive = true
        valueLabel.widthAnchor.constraint(equalToConstant: 60).isActive = true

        addSubview(stack)

        stack.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        stack.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        stack.topAnchor.constraint(equalTo: topAnchor).isActive = true
        stack.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }

    @objc func sliderChanged(_ sender: Any) {
        guard let slider = sender as? NSSlider else { return }

        valueLabel.stringValue = valueFormatter(slider.doubleValue)
        print("Slider now: \(slider.doubleValue)")

        delegate?.adjustable(self, changedValue: slider.doubleValue)
    }

    @objc func enabledChanged(_ sender: Any) {
        guard let checkbox = sender as? NSButton else { return }
        print("Enabled now: \(checkbox.state == .on)")

        delegate?.adjustable(self, changedEnabled: checkbox.state == .on)
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-11-01 09:20:02

如Willeke所链接的问题中所描述的,解决方案是确保init在引用self之前已经完成。(我有点惊讶编译器允许在属性初始化器中使用它)

错:

代码语言:javascript
复制
private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))

右图:

代码语言:javascript
复制
private lazy var slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private lazy var enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50948337

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档