SwiftUI macOS应用中NSTableView无法显示问题求助
SwiftUI macOS中NSTableView无法正常显示的问题
我是Swift新手,正在开发SwiftUI macOS(≥12.2)应用,尝试将NSTableView作为NSView的子视图添加,但表格视图无法在屏幕上显示。
更新记录
- 更新1:
- 文末已添加最小可复现示例
- 已根据@jnpdx的建议更新代码
- 注意:取消注释
configureTableView()中的//addSubview(tableView)行(即重复调用addSubview(tableView)),可在屏幕最底部看到一个窄表格。
- 更新2:似乎需要保留两处
addSubview(tableView)调用,才能让tableView成为CustomView的层级子视图并在其范围内显示,且不会创建新实例。目前问题变为表格位于应用视图底部(应在顶部)及确保文本框可见。
FilesView类实现代码
class FilesView: NSView { let files: Files @Published var selectedFile: AudioFile? = nil @Published var sortDescending = false var tableView = NSTableView() var nameColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "name")) var statusColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "status")) var dateColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "date")) var groupingColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "grouping")) var durationColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "duration")) init(files:Files){ self.files = files super.init(frame: .zero) configureTableView() } func addFile(file: AudioFile) { self.files.files.append(file) tableView.reloadData() } required init?(coder: NSCoder) { fatalError("init(coder:) 尚未实现") } func configureTableView() { print("进入 configureTableView()") tableView.delegate = self tableView.dataSource = self tableView.identifier = NSUserInterfaceItemIdentifier(rawValue: "cell") tableView.addTableColumn(nameColumn) tableView.addTableColumn(statusColumn) tableView.addTableColumn(dateColumn) tableView.addTableColumn(groupingColumn) tableView.addTableColumn(durationColumn) tableView.headerView = nil tableView.backgroundColor = .black tableView.usesAlternatingRowBackgroundColors = true tableView.gridStyleMask = .solidVerticalGridLineMask tableView.focusRingType = .none tableView.selectionHighlightStyle = .none tableView.rowSizeStyle = .default tableView.reloadData() //addSubview(tableView) // tableView 是 FilesView 的子视图,而 FilesView 是 CustomView 的子视图,当创建 CustomView 并传入 tableView 时,tableView 会被添加为 CustomView 的子视图。 } }
CustomView类实现代码
class CustomView: NSView { private let tableView: FilesView private let textView: TextBox init(tableView: FilesView, textView: TextBox) { self.tableView = tableView self.textView = textView super.init(frame: .zero) addSubview(tableView) addSubview(textView) } required init?(coder: NSCoder) { fatalError("init(coder:) 尚未实现") } override func layout() { super.layout() let tableViewHeight = frame.height * 0.7 let textViewHeight = frame.height * 0.3 tableView.frame = NSRect(x: 0, y: 0, width: frame.width, height: tableViewHeight) textView.frame = NSRect(x: 0, y: tableViewHeight, width: frame.width, height: textViewHeight) } }
ContentView中调用CustomView的代码
struct CustomViewRepresentable: NSViewRepresentable { let filesView = FilesView(files: Files()) let textBox = TextBox() func makeNSView(context: Context) -> NSView { let customView = CustomView(tableView: filesView, textView: textBox) return customView } func updateNSView(_ nsView: NSView, context: Context) { // 如有必要,更新NSView } typealias NSViewType = NSView }
ContentView的实现
private var customViewRepresentable: CustomViewRepresentable init(){ self.customViewRepresentable = CustomViewRepresentable() }
ContentView的body部分
var body: some View { VStack { customViewRepresentable } }
最小可复现示例
import SwiftUI import Foundation import Combine class FilesView: NSView { //let files: Files @Published var sortDescending = false var tableView = NSTableView() var nameColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "name")) var statusColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "status")) var dateColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "date")) var groupingColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "grouping")) var durationColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "duration")) init(){ super.init(frame: .zero) configureTableView() } required init?(coder: NSCoder) { fatalError("init(coder:) 尚未实现") } func configureTableView() { print("进入 configureTableView()") tableView.delegate = self tableView.dataSource = self tableView.identifier = NSUserInterfaceItemIdentifier(rawValue: "cell") tableView.addTableColumn(nameColumn) tableView.addTableColumn(statusColumn) tableView.addTableColumn(dateColumn) tableView.addTableColumn(groupingColumn) tableView.addTableColumn(durationColumn) tableView.headerView = nil tableView.backgroundColor = .black tableView.usesAlternatingRowBackgroundColors = true tableView.gridStyleMask = .solidVerticalGridLineMask tableView.focusRingType = .none tableView.selectionHighlightStyle = .none tableView.rowSizeStyle = .default tableView.reloadData() //addSubview(tableView) // tableView 是 FilesView 的子视图,而 FilesView 是 CustomView 的子视图,当创建 CustomView 并传入 tableView 时,tableView 会被添加为 CustomView 的子视图。 } } extension FilesView: NSTableViewDataSource { func numberOfRows(in tableView: NSTableView) -> Int { return 0 } } extension FilesView: NSTableViewDelegate { func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { guard let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "cell"), owner: nil) as? NSTableCellView else { return nil } if tableColumn == tableView.tableColumns[0] { cell.textField?.stringValue = "" } else if tableColumn == tableView.tableColumns[1] { cell.textField?.stringValue = "" } else if tableColumn == tableView.tableColumns[2] { cell.textField?.stringValue = "" } else if tableColumn == tableView.tableColumns[3] { cell.textField?.stringValue = "" } else if tableColumn == tableView.tableColumns[4]{ cell.textField?.stringValue = "" } return cell } } class TextBox: NSView { @State private var selectedOption = 0 // 0 = 删除线, 1 = 隐藏, 2 = 下划线 @State private var text = "" @State private var isTextBoxHidden = false var textEditor: some View { TextEditor(text: $text) .frame(minHeight: 200) .padding() .overlay( RoundedRectangle(cornerRadius: 10) .stroke(Color.gray, lineWidth: 2) ) } var exportButton: some View { HStack { Spacer() Button(action: { // 导出代码 }) { Text("导出") } Spacer() } } override func layout() { super.layout() // 布局视图 } } class CustomView: NSView { private let tableView: FilesView private let textView: TextBox init(tableView: FilesView, textView: TextBox) { self.tableView = tableView self.textView = textView super.init(frame: .zero) addSubview(tableView) addSubview(textView) } required init?(coder: NSCoder) { fatalError("init(coder:) 尚未实现") } override func layout() { super.layout() let tableViewHeight = frame.height * 0.7 let textViewHeight = frame.height * 0.3 tableView.frame = NSRect(x: 0, y: 0, width: frame.width, height: tableViewHeight) textView.frame = NSRect(x: 0, y: tableViewHeight, width: frame.width, height: textViewHeight) } } struct CustomViewRepresentable: NSViewRepresentable { let filesView = FilesView() let textBox = TextBox() func makeNSView(context: Context) -> NSView { let customView = CustomView(tableView: filesView, textView: textBox) return customView } func updateNSView(_ nsView: NSView, context: Context) { // 如有必要,更新NSView } typealias NSViewType = NSView } //let customViewRepresentable = CustomViewRepresentable() // init(){ // self.customViewRepresentable = CustomViewRepresentable() // } struct ContentView: View { private var customViewRepresentable: CustomViewRepresentable init(){ self.customViewRepresentable = CustomViewRepresentable() } // 遵循ObservableObject协议 var didChange = PassthroughSubject<Void, Never>() var body: some View { VStack { customViewRepresentable } } }
内容的提问来源于stack exchange,提问作者ballade4op52
相关产品推荐
相关产品推荐

