【问题标题】:IBDesignable custom NSControl class - frame not resizing in Interface BuilderIBDesignable 自定义 NSControl 类 - Interface Builder 中的框架未调整大小
【发布时间】:2021-07-31 21:15:20
【问题描述】:

这是针对 macOS,而不是 iOS ...谢谢。

我有一个非常简单的自定义滑块控件,它有 2 个@IBInspectable 属性——trackHeight 和knowHeight。 我希望 Interface Builder 中的控件框架能够调整大小以响应这 2 个属性的变化,以便用户在设计时获得视觉反馈。现在,这在运行时可以正常工作,但在 Interface Builder 中却不行。

在 Interface Builder 中发生的情况是:框架保持相同大小,但滑块的轨道和旋钮(由我自定义绘制)被拉伸。这不是我想要的。控件的框架应该改变。

我已经搜索了很多解决方案,这就是我的代码中的内容,但没有运气。请帮忙。提前致谢。

import Cocoa

@IBDesignable
class MySliderControl: NSControl {
    
    override init(frame frameRect: NSRect) {

        super.init(frame: frameRect)
        self.frame = NSMakeRect(frameRect.minX, frameRect.minY, 200, max(trackHeight, knobHeight))
    }
    
    required init?(coder: NSCoder) {
        
        super.init(coder: coder)
        self.frame = NSMakeRect(frame.minX, frame.minY, 200, max(trackHeight, knobHeight))
    }
    
    @IBInspectable var trackHeight: CGFloat = 4 {
        
        didSet {
            
            prepareForInterfaceBuilder()
            needsDisplay = true
        }
    }

    @IBInspectable var knobHeight: CGFloat = 10 {
        
        didSet {
            
            prepareForInterfaceBuilder()
            needsDisplay = true
        }
    }
    
    override func layout() {

        self.setFrameSize(intrinsicContentSize)
        super.layout()
    }
    
    override func prepareForInterfaceBuilder() {
        
        // Resize the frame as a function of trackHeight and knobHeight.

        self.setFrameSize(intrinsicContentSize)
        super.prepareForInterfaceBuilder()
    }
    
    // Width is constant (200), and height is the maximum of knobHeight and trackHeight.
    override var intrinsicContentSize: NSSize {
        NSMakeSize(200, max(trackHeight, knobHeight))
    }
    
    override func draw(_ dirtyRect: NSRect) {
        
        // Center knobRect with respect to barRect.
        let barRect = NSMakeRect(0, knobHeight / 2 - trackHeight / 2, 200, trackHeight)
        let knobRect = NSMakeRect(50, 0, 20, knobHeight)
        
        var path = NSBezierPath(rect: barRect)
        NSColor.gray.setFill()
        path.fill()
        
        path = NSBezierPath(rect: knobRect)
        NSColor.white.setFill()
        path.fill()
    }
}

【问题讨论】:

    标签: swift macos cocoa ibdesignable ibinspectable


    【解决方案1】:

    当覆盖 intrinsicContentSize 时,我们需要使它以通知 IB 它需要更新。这也会触发对draw(_ dirtyRect: NSRect) 的调用。

    试试这个:

    @IBDesignable
    class MySliderControl: NSControl {
        
        @IBInspectable var trackHeight: CGFloat = 4 {
            didSet {
                invalidateIntrinsicContentSize()
            }
        }
        
        @IBInspectable var knobHeight: CGFloat = 10 {
            didSet {
                invalidateIntrinsicContentSize()
            }
        }
        
        // Width is constant (200), and height is the maximum of knobHeight and trackHeight.
        override var intrinsicContentSize: NSSize {
            NSMakeSize(200, max(trackHeight, knobHeight))
        }
        
        override func draw(_ dirtyRect: NSRect) {
            
            // Vertically Center barRect and knobRect
            //  with respect to self.bounds
            let barRect = NSMakeRect(0, bounds.midY - trackHeight * 0.5, 200, trackHeight)
            let knobRect = NSMakeRect(50, bounds.midY - knobHeight * 0.5, 20, knobHeight)
            
            var path = NSBezierPath(rect: barRect)
            NSColor.gray.setFill()
            path.fill()
            
            path = NSBezierPath(rect: knobRect)
            NSColor.white.setFill()
            path.fill()
            
        }
        
        // unless we're adding some other code,
        //  none of these is needed
        
    //  override init(frame frameRect: NSRect) {
    //      super.init(frame: frameRect)
    //  }
    //  required init?(coder: NSCoder) {
    //      super.init(coder: coder)
    //  }
    //  override func layout() {
    //      super.layout()
    //  }
    //  override func prepareForInterfaceBuilder() {
    //      super.prepareForInterfaceBuilder()
    //  }
    
    }
    

    编辑 -- 哎呀,刚刚看到帖子上的日期。希望你已经解决了这个问题:)

    【讨论】:

    • 非常感谢您的回答!我目前正在进行另一个项目,但当我有机会时会尝试一下。干杯:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 2018-06-18
    • 2012-11-17
    • 1970-01-01
    相关资源
    最近更新 更多