I have made a simple demo using TableView here: https://github.com/deadcoder0904/TableViewDemo
I have used Defaults module as a dependency
My project looks like
All the code is in ViewController.swift
as follows -
import Cocoa
import Defaults
extension Defaults.Keys {
static let dreams = Defaults.Key<Array<String>>("dreams", default: [
"Hit the gym",
"Run daily",
"Become a millionaire",
"Become a better programmer",
"Achieve your dreams"
])
}
class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
@IBOutlet weak var table: NSTableView!
var dreams = defaults[.dreams]
var selectedRow:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
table.dataSource = self
table.delegate = self
}
override var acceptsFirstResponder : Bool {
return true
}
override func keyDown(with theEvent: NSEvent) {
if theEvent.keyCode == 51 {
removeDream()
}
}
func tableViewSelectionDidChange(_ notification: Notification) {
let table = notification.object as! NSTableView
selectedRow = table.selectedRow
}
func numberOfRows(in tableView: NSTableView) -> Int {
return dreams.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let dream = table.makeView(withIdentifier: tableColumn!.identifier, owner: self) as! NSTableCellView
dream.textField?.stringValue = dreams[row]
return dream
}
@IBAction func addTableRow(_ sender: Any) {
addNewDream()
}
@IBAction func removeTableRow(_ sender: Any) {
removeDream()
}
func addNewDream() {
dreams.append("Double Click or Press Enter to Add Item")
table.beginUpdates()
let last = dreams.count - 1
table.insertRows(at: IndexSet(integer: last), withAnimation: .effectFade)
table.scrollRowToVisible(last)
table.selectRowIndexes([last], byExtendingSelection: false)
table.endUpdates()
saveDreams()
}
func removeDream() {
if selectedRow >= dreams.count {
selectedRow = dreams.count - 1
}
if selectedRow != -1 {
dreams.remove(at: selectedRow)
table.removeRows(at: IndexSet(integer: selectedRow), withAnimation: .effectFade)
}
saveDreams()
}
func saveDreams() {
defaults[.dreams] = dreams
}
}
I want to do 2 things -
Get notified after Text Cell is edited so that I can save the changed data using Defaults module
After adding new Data by Clicking on the plus sign it adds Double Click or Press Enter to Add Item but what I want is I want to add Empty String which I can do with "" but I also want it to be focused & be editable so user can start entering text in it without having to Double Click or Press Enter .
I also want a solution in Swift 4 & not Objective-C. How to achieve this?
Use Cocoa Bindings, it's very powerful and saves a lot of boilerplate code.
Short tutorial:
Edit: To take full advantage of KVC the data source must be an NSObject
subclass with dynamic
properties
Create a simple class Dream
(the description
property is optional)
class Dream : NSObject { @objc dynamic var name : String init(name : String) { self.name = name } override var description : String { return "Dream " + name } }
In the view controller declare the data source array
var dreams = [Dream]()
and replace var selectedRow:Int = 0
with
@objc dynamic var selectedIndexes = IndexSet()
Go to Interface Builder
Select the table view, press ⌥⌘7 to go to the Bindings Inspector.
Bind Selection Indexes
to View Controller
Model Key Path selectedIndexes
.
Press ⌥⌘6 and connect the dataSource
(by drag&drop) to the view controller ( ) .
Select the text field File 1
in Table Cell View
in the table column. The easiest way is to ⌃⇧click in the text field area.
Press ⌥⌘7 and bind Value
to Table Cell View
Model Key Path objectValue.name
( ! )
In the view controller populate the data source array in viewDidLoad
( I don't know that framework so I leave it out) and reload the table view.
override func viewDidLoad() { super.viewDidLoad() let dreamNames = ["Hit the gym", "Run daily", "Become a millionaire", "Become a better programmer", "Achieve your dreams"] dreams = dreamNames.map{Dream(name: $0)} table.reloadData() }
Delete acceptsFirstResponder
tableViewSelectionDidChange
tableView:viewFor:row:
Add
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { return dreams[row] }
Replace addNewDream
with
func addNewDream() { let last = dreams.count dreams.append(Dream(name: "Double Click or Press Enter to Add Item")) table.insertRows(at: IndexSet(integer: last), withAnimation: .effectGap) table.scrollRowToVisible(last) table.selectRowIndexes([last], byExtendingSelection: false) saveDreams() }
Replace removeDream()
with
func removeDream() { guard let selectedRow = selectedIndexes.first else { return } dreams.remove(at: selectedRow) table.removeRows(at: IndexSet(integer: selectedRow), withAnimation: .effectFade) saveDreams() }
To save the array when the text was edited afterwards you have to implement the delegate method controlTextDidEndEditing(_:)
override func controlTextDidEndEditing(_ obj: Notification) {
saveDreams()
}
and in Interface Builder connect the delegate
of the text field in the table view to the view controller.
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.