编程创建NSGridView嵌入可编辑NSTextField时视图不显示问题
纯代码实现NSGridView嵌入可编辑NSTextField后整体不显示问题
问题描述
作为Swift与macOS开发新手,我习惯先为待实现功能搭建原型做验证。目前在纯代码创建的NSGridView中嵌入NSTextField时遇到了异常:
- 将NSTextField设置为静态标签状态时,显示效果完全符合预期
- 调整为可编辑状态后,整个NSGridView会完全消失,没有任何可见内容
经过数小时的资料检索、反复试错排查,始终没有定位到问题根源,推测和布局逻辑相关,但尝试的各类调整方案都没有生效。
当前实现代码写在主窗口关联的视图控制器中,具体如下:
override func viewDidAppear() { let t1 = NSTextField (string: "r0c0") let t2 = NSTextField (string: "r0c1") gridView = NSGridView (views: [ [t1,t2] ]) gridView?.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(gridView!) let winContent = view.window?.contentView! gridView?.centerXAnchor.constraint(equalTo: winContent!.centerXAnchor).isActive = true gridView?.centerYAnchor.constraint(equalTo: winContent!.centerYAnchor).isActive = true }
问题根源
这个异常本质是固有尺寸塌陷导致的:
- 当NSTextField为静态标签(
isEditable = false)状态时,系统会根据文本内容自动计算出明确的固有尺寸(intrinsicContentSize),这个尺寸会自动撑开NSGridView,让它具备可见的宽高 - 当NSTextField被设置为可编辑状态时,系统会自动将它的固有尺寸设为无(对应值
NSView.noIntrinsicMetric)。当前代码只给NSGridView添加了居中约束,没有任何约束定义它的宽高,最终整个NSGridView的宽高会塌缩为0,自然完全不可见
解决方案
可以根据实际开发需求,选择以下任意一种修复方案:
- 给可编辑的NSTextField设置固定高度
可编辑输入框通常需要匹配系统标准输入控件的高度,给文本框添加高度约束即可恢复布局,同时建议开启边框让可编辑状态更符合用户预期,示例代码:override func viewDidAppear() { let t1 = NSTextField(string: "r0c0") t1.isEditable = true let t2 = NSTextField(string: "r0c1") t2.isEditable = true // 批量配置可编辑文本框的样式与布局约束 [t1, t2].forEach { textField in // 设置和系统标准输入框匹配的高度 textField.heightAnchor.constraint(equalToConstant: 24).isActive = true // 开启圆角边框,提升可识别性 textField.isBezeled = true textField.bezelStyle = .roundedBezel } gridView = NSGridView(views: [[t1, t2]]) guard let gridView = gridView else { return } gridView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(gridView) guard let contentView = view.window?.contentView else { return } NSLayoutConstraint.activate([ gridView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), gridView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) ]) } - 给NSGridView设置最小宽高约束
如果不想逐个给文本框添加约束,可以直接给NSGridView指定最小宽高,避免布局塌缩:// 在原有居中约束的基础上追加最小尺寸约束 gridView?.widthAnchor.constraint(greaterThanOrEqualToConstant: 200).isActive = true gridView?.heightAnchor.constraint(greaterThanOrEqualToConstant: 40).isActive = true - 给NSGridView添加自适应边缘约束
如果需要让gridView随窗口大小自动调整宽度,可以在居中约束的基础上追加左右边缘约束,自动撑开布局:guard let contentView = view.window?.contentView else { return } NSLayoutConstraint.activate([ gridView!.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), gridView!.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), gridView!.leadingAnchor.constraint(greaterThanOrEqualTo: contentView.leadingAnchor, constant: 20), gridView!.trailingAnchor.constraint(lessThanOrEqualTo: contentView.trailingAnchor, constant: -20) ])
注意:如果是在临时作用域(比如方法内部)创建NSGridView,一定要保证它被父视图强引用,否则会被ARC回收,同样会出现视图不显示的问题。当前代码中gridView是控制器的类属性,强引用关系正常,不会触发回收问题。
内容的提问来源于stack exchange,提问作者Hayseed
相关产品推荐
相关产品推荐

