I am writing an application using MacOs Big Sur with Xcode 12.2.
I am trying to implement a table view for a contact list (from examples on the internet).
Most of the code is for IOS en hard to port to MacOS.
For the most functionalities, the app is working very well.
I cannot succeed in implementing headers/footers for sections.
I did succeed with a previous project built around CollectionView.
But I cannot see the analogy between CollectionView and TableView. In CollectionView I used a nib for header/footers.
Here are the pieces of code for the Diffable Datasource example.
I hope somebody can help solving my problem.
'''
override func viewDidLoad() {
tableView.delegate = self
DataSource = makeDataSource()
tableView.dataSource = DataSource
update(with:ContactList(all: Contact.all,
friends: [],
family: [],
coworkers: []),
animate: true)
}
func makeDataSource() -> NSTableViewDiffableDataSource<Section, Contact> {
let reuseIdentifier = ContactTableCell.reuseIdentifier
return NSTableViewDiffableDataSource( tableView: tableView, cellProvider: { tableView, column, indexPath, contact in
guard let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(reuseIdentifier), owner: self) as? ContactTableCell else {
print("Failed to create results cell")
return NSView()
}
cell.configure(with: contact)
return cell
}
)
}
func update(with list: ContactList, animate: Bool = true) {
var snapshot = NSDiffableDataSourceSnapshot<Section, Contact>()
snapshot.appendSections([Section.all, Section.family,Section.coworkers,Section.friends])
snapshot.appendItems(list.all, toSection: .all)
snapshot.appendItems(list.family, toSection: .family)
snapshot.appendItems(list.coworkers, toSection: .coworkers)
snapshot.appendItems(list.friends, toSection: .friends)
DataSource.apply(snapshot, animatingDifferences: animate)
}
class ContactTableCell: NSTableCellView{
@IBOutlet weak var firstname: NSTextField!
@IBOutlet weak var lastname: NSTextField!
@IBOutlet weak var email: NSTextField!
@IBOutlet weak var userView: NSImageView!
static var reuseIdentifier: String {
return NSUserInterfaceItemIdentifier(String(describing: ContactTableCell.self)).rawValue
}
func configure(with contact:Contact){
print("\(#function)")
self.userView.imageScaling = .scaleProportionallyDown
self.userView.image = NSImage(contentsOfFile:contact.imagePath)
self.firstname.stringValue = contact.firstName //"\(contact.firstName) \(contact.lastName)"
self.lastname.stringValue = contact.lastName //contact.emailAddress
self.email.stringValue = contact.emailAddress
}
}
class SectionHeaderView: NSTableHeaderView {
static var reuseIdentifier: String {
return NSUserInterfaceItemIdentifier(String(describing: SectionHeaderView.self)).rawValue
}
lazy var headerLabel: NSTextField = {
print("\(#function)")
let label = NSTextField()
label.textColor = .red
label.font = NSFont.systemFont(ofSize: 15, weight: .medium)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func draw(_ dirtyRect: NSRect) {
print("\(#function)")
super.draw(dirtyRect)
// Drawing code here.
}
required init?(coder: NSCoder) {
print("\(#function)")
super.init(coder: coder)
setupView()
}
func setupView() {
print("\(#function)")
addSubview(headerLabel)
setupLayout()
}
func setupLayout() {
print("\(#function)")
NSLayoutConstraint.activate([
headerLabel.topAnchor.constraint(equalTo: self.topAnchor ,constant: 2),
headerLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor,
constant: -2),
headerLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor,
constant: 8),
headerLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor,
constant: -8),
])
}
} '''
A table view in macOS works a bit different, because there are no explicit sections like in iOS. The section headers are Group Rows which are inline as a part of the data source array.
To display section headers in the diffable data source create a struct rather than an enum
struct Section : Hashable {
let name : String
}
Extend makeDataSource()
func makeDataSource() -> NSTableViewDiffableDataSource<Section, Contact>
{
let reuseIdentifier = ContactTableCell.reuseIdentifier
let dataSource = NSTableViewDiffableDataSource<Section,Contact>( tableView: tableView, cellProvider: { tableView, column, row, contact in
let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(reuseIdentifier), owner: self) as! ContactTableCell
cell.configure(with: contact)
return cell
})
dataSource.sectionHeaderViewProvider = { tableView, row, section in
let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "group"), owner: self) as! NSTableCellView
cell.textField?.stringValue = section.name
return cell
}
return dataSource
}
and populate the data source
func update(with list: ContactList, animate: Bool = true) {
var snapshot = NSDiffableDataSourceSnapshot<Section, Contact>()
let sections = [Section(name: "all"), Section(name: "family"), Section(name: "coworkers"), Section(name: "friends")
snapshot.appendSections(sections)
snapshot.appendItems(list.all, toSection: sections[0])
snapshot.appendItems(list.family, toSection: sections[1])
snapshot.appendItems(list.coworkers, toSection: sections[2])
snapshot.appendItems(list.friends, toSection: sections[3])
DataSource.apply(snapshot, animatingDifferences: animate)
}
I ran into a similar problem, and looking at the source code, what might need to be done in your case is set these to your diffableDataSource:
@property (copy,nullable) NSTableViewDiffableDataSourceRowProvider rowViewProvider;
@property (copy,nullable) NSTableViewDiffableDataSourceSectionHeaderViewProvider sectionHeaderViewProvider;
I don't think there is a section footer API, so you might need to show some sort of footer on the last cell item in the section.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.