不使用Interface Builder,代码创建NSOutlineView无数据问题求助
NSOutlineView 空白问题的修复方案
核心问题分析与修复步骤
1. 根节点未持久化存储
viewDidLoad中创建的rootNode是局部变量,控制器的数据源方法无法访问到它。需要将其改为控制器的属性:
private var rootNode: Node! // 添加根节点属性
在viewDidLoad中初始化数据并刷新视图:
override func viewDidLoad() { super.viewDidLoad() rootNode = Node(name: "Root Node") let childNode1 = Node(name: "Child Node 1") let childNode2 = Node(name: "Child Node 2") rootNode.addChild(childNode1) rootNode.addChild(childNode2) outlineView.reloadData() // 数据初始化完成后再刷新 }
2. 数据源方法逻辑错误
当前numberOfChildrenOfItem方法中,当item为nil(代表根层级)时返回0,导致OutlineView认为没有根节点。修改数据源方法:
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { if let item = item as? Node { return item.children.count } else { // 根层级返回根节点数量 return rootNode != nil ? 1 : 0 } } func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { if let item = item as? Node { return item.children[index] } else { // 返回根节点 return rootNode! } }
3. NSOutlineView 缺少列
NSOutlineView必须至少有一列才能显示内容,添加列并设置标识符:
// 创建outlineView后添加列 let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "MainColumn")) outlineView.addTableColumn(column)
4. 滚动视图约束问题
当前scrollview使用frame布局且未设置自身约束,同时outlineView的约束会与scrollview的documentView自动布局冲突。修改为约束布局:
// 创建scrollview时关闭自动布局转换 let scrollview = NSScrollView() scrollview.translatesAutoresizingMaskIntoConstraints = false scrollview.documentView = outlineView view.addSubview(scrollview) // 给scrollview添加约束固定在父视图中 NSLayoutConstraint.activate([ scrollview.centerXAnchor.constraint(equalTo: view.centerXAnchor), scrollview.centerYAnchor.constraint(equalTo: view.centerYAnchor), scrollview.widthAnchor.constraint(equalToConstant: 800), scrollview.heightAnchor.constraint(equalToConstant: 600) ])
5. 代码语法错误
删除OutlineViewController类末尾多余的}。
修改后的完整代码
class OutlineViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate { // MARK: - Properties private var outlineView: NSOutlineView! private var rootNode: Node! // 根节点属性 // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() // 初始化数据 rootNode = Node(name: "Root Node") let childNode1 = Node(name: "Child Node 1") let childNode2 = Node(name: "Child Node 2") rootNode.addChild(childNode1) rootNode.addChild(childNode2) // 数据初始化完成后刷新视图 outlineView.reloadData() } override func loadView() { view = NSView() view.translatesAutoresizingMaskIntoConstraints = false // 创建大纲视图 outlineView = NSOutlineView() outlineView.translatesAutoresizingMaskIntoConstraints = false outlineView.rowHeight = 50 // 添加列(必须步骤) let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "MainColumn")) outlineView.addTableColumn(column) // 设置代理和数据源 outlineView.delegate = self outlineView.dataSource = self // 创建滚动视图 let scrollview = NSScrollView() scrollview.translatesAutoresizingMaskIntoConstraints = false scrollview.documentView = outlineView view.addSubview(scrollview) // 约束滚动视图 NSLayoutConstraint.activate([ scrollview.centerXAnchor.constraint(equalTo: view.centerXAnchor), scrollview.centerYAnchor.constraint(equalTo: view.centerYAnchor), scrollview.widthAnchor.constraint(equalToConstant: 800), scrollview.heightAnchor.constraint(equalToConstant: 600) ]) } // MARK: - NSOutlineViewDataSource func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { if let item = item as? Node { return item.children[index] } else { // 返回根节点 return rootNode! } } func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { guard let item = item as? Node else { return false } return item.children.count > 0 } func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { if let item = item as? Node { return item.children.count } else { // 根层级返回根节点数量 return rootNode != nil ? 1 : 0 } } // MARK: - NSOutlineViewDelegate func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { guard let node = item as? Node else { return nil } let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: TableCellView.identifier) guard let cell = outlineView.makeView(withIdentifier: cellIdentifier, owner: self) as? TableCellView else { let cell = TableCellView() cell.identifier = cellIdentifier return cell } // 根据节点内容设置单元格 cell.profileImage.image = NSImage(named: node.name.contains("1") ? "boy" : "girl") cell.label.stringValue = node.name return cell } } class Node { let name: String var children: [Node] = [] init(name: String) { self.name = name } func addChild(_ child: Node) { children.append(child) } } class TableCellView: NSTableCellView { static var identifier = "TableCell" var profileImage = NSImageView() var label = NSTextField(labelWithString: "") override init(frame frameRect: NSRect) { super.init(frame: frameRect) setupUI() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupUI() { addSubview(profileImage) addSubview(label) profileImage.wantsLayer = true profileImage.animates = true profileImage.layer?.cornerRadius = 45 label.isEditable = false label.alignment = .center label.font = .boldSystemFont(ofSize: 20) // 关闭自动布局转换 profileImage.translatesAutoresizingMaskIntoConstraints = false label.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ profileImage.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 50), profileImage.widthAnchor.constraint(equalToConstant: 90), profileImage.topAnchor.constraint(equalTo: topAnchor, constant: 20), profileImage.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20), label.leadingAnchor.constraint(equalTo: profileImage.trailingAnchor, constant: 20), label.centerYAnchor.constraint(equalTo: centerYAnchor), label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20) ]) } }
内容的提问来源于stack exchange,提问作者RRSK01_11
相关产品推荐
相关产品推荐

