与UIView的systemLayoutSizeFitting等效的NSView尺寸计算方法
在NSView中基于约束和目标尺寸计算最优尺寸
NSView原生的fittingSize仅能返回满足约束的最小尺寸,没有直接对应UIView的systemLayoutSizeFitting系列方法的API,但可以通过扩展NSView,利用临时约束结合优先级调整来实现完全对齐的功能。
实现对应UIView的两个方法
下面是NSView的扩展代码,实现与UIView两个systemLayoutSizeFitting方法逻辑一致的功能:
import AppKit extension NSView { // 对应UIView的func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize { return systemLayoutSizeFitting( targetSize, withHorizontalFittingPriority: .defaultHigh, verticalFittingPriority: .defaultHigh ) } // 对应UIView的带优先级参数的systemLayoutSizeFitting方法 func systemLayoutSizeFitting( _ targetSize: CGSize, withHorizontalFittingPriority horizontalPriority: NSLayoutConstraint.Priority, verticalFittingPriority: NSLayoutConstraint.Priority ) -> CGSize { var temporaryConstraints = [NSLayoutConstraint]() // 添加临时宽度约束(仅当目标宽度不是无限大时) if targetSize.width != .greatestFiniteMagnitude { let widthConstraint = widthAnchor.constraint(equalToConstant: targetSize.width) widthConstraint.priority = horizontalPriority widthConstraint.isActive = true temporaryConstraints.append(widthConstraint) } // 添加临时高度约束(仅当目标高度不是无限大时) if targetSize.height != .greatestFiniteMagnitude { let heightConstraint = heightAnchor.constraint(equalToConstant: targetSize.height) heightConstraint.priority = verticalFittingPriority heightConstraint.isActive = true temporaryConstraints.append(heightConstraint) } // 计算满足临时约束与原有约束的最优尺寸 let optimalSize = fittingSize // 清理临时约束,不影响视图后续布局 NSLayoutConstraint.deactivate(temporaryConstraints) return optimalSize } }
逻辑说明
- 无优先级参数的方法:默认使用
.defaultHigh优先级,和UIView原生方法的默认行为一致,即尽量贴近目标尺寸,同时不打破视图自身的约束。 - 带优先级参数的方法:
- 根据传入的目标尺寸创建临时宽/高约束,约束的优先级由参数指定
- 激活临时约束后调用
fittingSize,此时计算出的尺寸会在原有约束的基础上,尽可能贴合目标尺寸(优先级越高,越倾向于贴近目标尺寸;优先级越低,越优先满足原有约束) - 计算完成后立即移除临时约束,避免干扰视图的正常布局流程
- 无限大尺寸处理:当目标尺寸的某一维度传入
.greatestFiniteMagnitude时,该维度会忽略临时约束,直接返回满足原有约束的最小尺寸,和原生fittingSize的对应维度逻辑一致。
内容的提问来源于stack exchange,提问作者Florian Karimkhan-Zand
相关产品推荐
相关产品推荐

