问题
I am trying to remove a row from my NStableView by swipe function. I am using macOS 10.13 and swift 4 and pretty new to swift coding.
I tried to follow: Implementing NSTableViewRowAction using Swift but it did not work for me.
And this is how I implement it:
public func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge: NSTableView.RowActionEdge) -> [NSTableViewRowAction] {
// left swipe
if edge == .trailing {
let deleteAction = NSTableViewRowAction(style: .destructive, title: "Delete", handler: { (rowAction, row) in
// action code
List_Symbol.remove(at: row)
List_Price.remove(at: row)
List_Procent.remove(at: row)
List_Volume.remove(at: row)
})
deleteAction.backgroundColor = NSColor.red
return [deleteAction]
}
let archiveAction = NSTableViewRowAction(style: .regular, title: "Archive", handler: { (rowAction, row) in
// action code
})
return [archiveAction]
}
Any other suggestion how to delete row in NSTableView by swiping?
The Whole code:
import Cocoa
import Alamofire
var List_Symbol = ["AAPL"]
var List_Price = [10.0]
var List_Procent = [1.0]
var List_Volume = [100]
class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
@IBOutlet weak var tableView: NSTableView!
@IBOutlet weak var input: NSTextField!
@IBAction func additem(_ sender: Any) {
if (input.stringValue != ""){
var Stock = StockInformation(symbol: input.stringValue)
Stock.GetStockInformation {
List_Symbol.append(Stock.Symbol)
List_Price.append(Stock.Price)
List_Procent.append(Stock.Percent)
List_Volume.append(Stock.Volume)
self.tableView.reloadData()
}
input.stringValue = ""
}
self.tableView.reloadData()
}
public func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge: NSTableView.RowActionEdge) -> [NSTableViewRowAction] {
// left swipe
if edge == .trailing {
let deleteAction = NSTableViewRowAction(style: .destructive, title: "Delete", handler: { (rowAction, row) in
// action code
List_Symbol.remove(at: row)
List_Price.remove(at: row)
List_Procent.remove(at: row)
List_Volume.remove(at: row)
tableView.removeRows(at: IndexSet(integer: row), withAnimation: .effectFade)
})
deleteAction.backgroundColor = NSColor.red
return [deleteAction]
}
let archiveAction = NSTableViewRowAction(style: .regular, title: "Archive", handler: { (rowAction, row) in
// action code
})
return [archiveAction]
}
override func viewDidAppear() {
tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
}
func numberOfRows(in tableView: NSTableView) -> Int{
return List_Symbol.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any?{
var identifierStr = tableColumn!.identifier
if (identifierStr.rawValue == "StockNameCellID"){
return List_Symbol[row]
}else if (identifierStr.rawValue == "PriceCellID"){
return List_Price[row]
}else if (identifierStr.rawValue == "PercentCellID"){
return List_Procent[row]
}else if (identifierStr.rawValue == "VolumeCellID"){
return List_Volume[row]
}
tableView.reloadData()
return nil
}
}
回答1:
Don't use multiple arrays as data source, that's horrible.
In macOS you can replace a lot of boilerplate code with Cocoa Bindings
• Use a class inherited from NSObject as data source
@objcMembers
class Stock : NSObject {
dynamic var symbol : String
dynamic var price : Double
dynamic var procent : Double
dynamic var volume : Int
init(symbol : String, price : Double, procent : Double, volume : Int) {
self.symbol = symbol
self.price = price
self.procent = procent
self.volume = volume
}
}
• Declare the data source array within the view controller
@objc var stocks = [Stock]()
• In additem create a new Stock item, rather then reloading the table view insert only the row with a smart animation
@IBAction func additem(_ sender: Any) {
if !input.stringValue.isEmpty {
let stock = StockInformation(symbol: input.stringValue)
stock.GetStockInformation {
let newStock = Stock(symbol: stock.Symbol, price: stock.Price, procent: stock.Percent, volume: stock.Volume)
let insertionIndex = IndexSet(integer: stocks.count)
self.stocks.append(newStock)
self.tableView.insertRows(at: insertionIndex, withAnimation: .effectGap)
self.input.stringValue = ""
}
}
}
• objectValueFor and numberOfRows are only one line respectively
func numberOfRows(in tableView: NSTableView) -> Int{
return stocks.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return stocks[row]
}
• The delete action is
public func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge: NSTableView.RowActionEdge) -> [NSTableViewRowAction] {
print("swipe")
// left swipe
if edge == .trailing {
let deleteAction = NSTableViewRowAction(style: .destructive, title: "Delete", handler: { (rowAction, row) in
// action code
self.stocks.remove(at: row)
tableView.removeRows(at: IndexSet(integer: row), withAnimation: .effectFade)
})
deleteAction.backgroundColor = NSColor.red
return [deleteAction]
}
}
• In Interface Builder connect datasource and delegate of the table view to the view controller. Further press ⌥⌘7 (Bindings Inspector), then select each Table View Cell (the NSTextField not NSTextFieldCell and not Table Cell View!) and bind the Value to Table Cell View and Model Key Path to the corresponding property (objectValue.symbol, objectValue.price etc.)
You can even use more Cocoa Bindings by binding the content of the table view to the stocks array. Then you can get rid of the datasource and its methods.
来源:https://stackoverflow.com/questions/51692877/remove-row-from-nstableview-by-swiping