Autolayout:使用NSUserInterfaceCompression的条件内容压缩阻力优先级



我通过子类化NSView(不使用任何现有控件/按钮;它是一个完全自定义的视图,具有一组复杂的内部约束(创建了一个自定义段控件(Cocoa/macOS(,它有两种模式:

  1. 默认情况下,水平显示所有分段:[sece 1][sece 2][sece 3]
  2. 当所有线段都无法适应窗口/当前约束集(受周围控件及其约束的影响(时,将单个线段显示为下拉列表:[线段1🔽 ]

这很好,我可以在运行时在两种模式之间切换/设置动画。然而,我最终想要实现的是基于当前窗口大小的自动扩展/压缩(或者在用户调整窗口大小时在两者之间切换(。我希望这个控件可以重复使用,而不需要窗口/视图控制器来管理切换,并试图避免在基于超级视图的layout调用内部的"粗略"估计的约束之间切换(这感觉像是黑客攻击(。

NSSegmentControlNSButton等似乎实现了NSUserInterfaceCompression,这应该是我试图实现的,然而,在初始布局/内部内容大小刷新/窗口大小调整等过程中,该协议中的任何方法都没有被调用。我也发现文档缺乏;我发现的唯一有用的信息是在CCD_ 6头文件中。该协议似乎正是我所需要的——系统调用适当的方法来确定最小/理想大小,并要求控件在空间紧张时自行调整大小。

值得一提的是,我也尝试过对NSButton进行子类化(出于各种原因,我需要坚持对NSView进行子类划分(,但这也没有触发任何这些方法(即从NSUserInterfaceCompression开始(。

知道我错过了什么吗?

好奇。。。稍微搜索一下,我就可以找到关于NSUserInterfaceCompression非常少的信息?

不确定你需要做什么,但这种方法可能对你有用:

class SegTestView: NSView {

let segCtrl = NSSegmentedControl()
var curWidth: CGFloat = 0

override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
addSubview(segCtrl)
segCtrl.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
segCtrl.topAnchor.constraint(equalTo: topAnchor),
segCtrl.leadingAnchor.constraint(equalTo: leadingAnchor),
segCtrl.trailingAnchor.constraint(equalTo: trailingAnchor),
segCtrl.bottomAnchor.constraint(equalTo: bottomAnchor),
])
}

override func layout() {
super.layout()

// only execute if bounds.width has changed
if curWidth != bounds.width {
curWidth = bounds.width
segCtrl.segmentCount = 3
segCtrl.setLabel("First", forSegment: 0)
segCtrl.setLabel("Second", forSegment: 1)
segCtrl.setLabel("Third", forSegment: 2)
if segCtrl.intrinsicContentSize.width > bounds.size.width {
segCtrl.segmentCount = 1
segCtrl.setLabel("Single 🔽", forSegment: 0)
} else {
// in case you want to do something else here...
}
}

}
}

似乎NSUserInterfaceCompression是一条死胡同。目前,我已经将此报告为关于文档不足的反馈/错误(FB9062854(。

我最终解决这个问题的方法是:

  1. 在自定义控件上设置以下内容压缩:
let priorityToResistCompression = contentCompressionResistancePriority(for: .horizontal)
setContentCompressionResistancePriority(priorityToResistCompression, for: .horizontal)
  1. 控件内的最后一段(内部NSView子视图(有一个优先级为defaultLow的拖尾锚,允许其断裂,以便控件可以继续拉伸

  2. 覆盖setFrameSize,并确定要显示的最佳模式(压缩的、单个分段作为下拉菜单,或者所有分段(如果它们可以水平放置((。然后调用invalidateIntrinsicContentSize()以重新计算内容大小。

  3. 使用上一步中确定的模式,覆盖intrinsicContentSize并提供正确的大小(最小压缩版本或所有段都可以容纳的版本(。

通过这种方式,控件将所有这些功能封装到一个单独的NSView子类中,并在调整窗口大小时免除托管此控件的任何超级视图/窗口设置正确大小的责任。

相关内容

  • 没有找到相关文章

最新更新