smr*_*smr 3 macos nsoutlineview appkit macos-big-sur
我已经启动了一个新的 macOS 项目(目前在 Big Sur beta 3 上),节点NSOutlineView似乎已损坏。分不清这是我还是操作系统。
这是一个演示该问题的示例项目。还有一个图像...
正如您所看到的,单元与扩展 V 形重叠。单击任一 V 形图标会将第一行恢复到正确的布局,但不会将第二行恢复到正确的布局。此外,自动保存方法persistentObjectForItem和itemForPersistentObject永远不会被调用。
测试项目非常简单——我所做的就是将SourceView组件从视图库添加到默认应用程序项目,并将委托/数据源连接到视图控制器。还检查Autosave Expanded Items了 IB 并在字段中输入了名称Autosave。这是完整的控制器代码:
class ViewController: NSViewController {
@IBOutlet var outlineView: NSOutlineView?
let data = [Node("First item", 1), Node("Second item", 2)]
}
extension ViewController: NSOutlineViewDataSource {
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
data[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
true
}
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
item == nil ? data.count : 0
}
func outlineView(_ outlineView: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? {
item
}
func outlineView(_ outlineView: NSOutlineView, persistentObjectForItem item: Any?) -> Any? {
(item as? Node)?.id
}
func outlineView(_ outlineView: NSOutlineView, itemForPersistentObject object: Any) -> Any? {
guard let id = object as? Int else { return nil }
return data.first { $0.id == id }
}
}
extension ViewController: NSOutlineViewDelegate {
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
guard let node = item as? Node else {
preconditionFailure("Invalid data item \(item)")
}
let view = outlineView.makeView(withIdentifier: nodeCellIdentifier, owner: self) as? NSTableCellView
view?.textField?.stringValue = node.name
view?.imageView?.image = NSImage(systemSymbolName: node.icon, accessibilityDescription: nil)
return view
}
}
final class Node {
let id: Int
let name: String
let icon: String
init(_ name: String, _ id: Int, _ icon: String = "folder") {
self.id = id
self.name = name
self.icon = icon
}
}
private let nodeCellIdentifier = NSUserInterfaceItemIdentifier("DataCell")
Run Code Online (Sandbox Code Playgroud)
还有 Mac 开发人员可以提供帮助吗?
什么是来源列表?它NSOutlineView(它是 的子类
NSTableView)经过特殊
处理。查找器截图:
要创建源列表,您只需将该
selectionHighlightStyle属性设置为
.sourceList。文档说:
NSTableView的源列表样式。在 10.5 上,浅蓝色渐变用于突出显示选定的行。
它到底有什么作用?跳转到Xcode 中的定义并阅读注释(不包含在文档中):
NSTableView的源列表样式。在 10.10 及更高版本中,模糊选择用于突出显示行。在此之前,使用的是浅蓝色渐变。注意:具有drawsBackground属性的单元格应将其设置为NO。否则,它们将覆盖 NSTableView 所做的突出显示。设置此样式将会产生将背景颜色设置为“源列表”背景颜色的副作用。此外,在 NSOutlineView 中,更改了以下属性以获得标准的“源列表”外观:indentationPerLevel、rowHeight 和 intercellSpacing。调用 setSelectionHighlightStyle: 后,可以根据需要更改任何其他属性。在 10.11 中,如果背景颜色已从“源列表”背景颜色更改为其他颜色,则表格将不再将选择内容绘制为源列表模糊样式,而是会进行正常的蓝色突出显示。
由于您位于大苏尔,请注意它SelectionHighlightStyle.sourceList已被弃用。应该使用style
& effectiveStyle。
代码:
FinderLikeSidebar那里有)
NSOutlineView Items FinderLikeSidebar密钥下的用户默认值中@IBOutlet var outlineView: NSOutlineView!GroupCell正如您所看到的,它几乎与 Finder 类似 - 第二级仍然缩进。原因是文档节点是可扩展的(有子节点)。我把它们放在这里是为了演示自动保存。
如果您想将所有二级节点移至左侧,只需删除它们即可。
没什么可说的,除了 - 阅读评论:)
import Cocoa
// Sample Node class covering groups & regular items
class Node {
let id: Int
let title: String
let symbolName: String?
let children: [Node]
let isGroup: Bool
init(id: Int, title: String, symbolName: String? = nil, children: [Node] = [], isGroup: Bool = false) {
self.id = id
self.title = title
self.symbolName = symbolName
self.children = children
self.isGroup = isGroup
}
convenience init(groupId: Int, title: String, children: [Node]) {
self.init(id: groupId, title: title, children: children, isGroup: true)
}
}
extension Node {
var cellIdentifier: NSUserInterfaceItemIdentifier {
// These must match identifiers in Main.storyboard
NSUserInterfaceItemIdentifier(rawValue: isGroup ? "GroupCell" : "DataCell")
}
}
extension Array where Self.Element == Node {
// Search for a node (recursively) until a matching element is found
func firstNode(where predicate: (Element) throws -> Bool) rethrows -> Element? {
for element in self {
if try predicate(element) {
return element
}
if let matched = try element.children.firstNode(where: predicate) {
return matched
}
}
return nil
}
}
class ViewController: NSViewController, NSOutlineViewDelegate, NSOutlineViewDataSource {
@IBOutlet var outlineView: NSOutlineView!
let data = [
Node(groupId: 1, title: "Favorites", children: [
Node(id: 11, title: "AirDrop", symbolName: "wifi"),
Node(id: 12, title: "Recents", symbolName: "clock"),
Node(id: 13, title: "Applications", symbolName: "hammer")
]),
Node(groupId: 2, title: "iCloud", children: [
Node(id: 21, title: "iCloud Drive", symbolName: "icloud"),
Node(id: 22, title: "Documents", symbolName: "doc", children: [
Node(id: 221, title: "Work", symbolName: "folder"),
Node(id: 221, title: "Personal", symbolName: "folder.badge.person.crop"),
])
]),
]
override func viewWillAppear() {
super.viewWillAppear()
// Expanded items are saved in the UserDefaults under the key:
//
// "NSOutlineView Items \(autosaveName)"
//
// By default, this value is not present. When you expand some nodes,
// an array with persistent objects is saved. When you collapse all nodes,
// the array is removed from the user defaults (not an empty array,
// but back to nil = removed).
//
// IOW there's no way to check if user already saw this source list,
// modified expansion state, etc. We will use custom key for this
// purpose, so we can expand group nodes (top level) when the source
// list is displayed for the first time.
//
// Next time, we wont expand anything and will honor autosaved expanded
// items.
if UserDefaults.standard.object(forKey: "FinderLikeSidebarAppeared") == nil {
data.forEach {
outlineView.expandItem($0)
}
UserDefaults.standard.set(true, forKey: "FinderLikeSidebarAppeared")
}
}
// Number of children or groups (item == nil)
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
item == nil ? data.count : (item as! Node).children.count
}
// Child of a node or group (item == nil)
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
item == nil ? data[index] : (item as! Node).children[index]
}
// View for our node
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
guard let node = item as? Node,
let cell = outlineView.makeView(withIdentifier: node.cellIdentifier, owner: self) as? NSTableCellView else {
return nil
}
cell.textField?.stringValue = node.title
if !node.isGroup {
cell.imageView?.image = NSImage(systemSymbolName: node.symbolName ?? "folder", accessibilityDescription: nil)
}
return cell
}
// Mark top level items as group items
func outlineView(_ outlineView: NSOutlineView, isGroupItem item: Any) -> Bool {
(item as! Node).isGroup
}
// Every node is expandable if it has children
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
!(item as! Node).children.isEmpty
}
// Top level items (group items) are not selectable
func outlineView(_ outlineView: NSOutlineView, shouldSelectItem item: Any) -> Bool {
!(item as! Node).isGroup
}
// Object to save in the user defaults (NSOutlineView Items FinderLikeSidebar)
func outlineView(_ outlineView: NSOutlineView, persistentObjectForItem item: Any?) -> Any? {
(item as! Node).id
}
// Find an item from the saved object (NSOutlineView Items FinderLikeSidebar)
func outlineView(_ outlineView: NSOutlineView, itemForPersistentObject object: Any) -> Any? {
guard let id = object as? Int else { return nil }
return data.firstNode { $0.id == id }
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1247 次 |
| 最近记录: |