Reputation: 644
I have a use case where I need to change the title of the UITableViewRowAction
. For example, I have a restaurant cell, and when swipe right I show "bookmark(104)" where "bookmark" is the action and 104 means there have been 104 people bookmarked it. When click on it, I want it to change to "bookmark(105)" because obviously there's a new user(the current user himself) has bookmarked it. How do I do that? Tried the below code and it doesn't work.
let likeAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "bookmark\n\(count)", handler:{(action, indexpath) -> Void in
....
count++
action.title = "bookmark\n\(count)"
});
Upvotes: 4
Views: 1490
Reputation: 42449
Here's a quick and dirty example.
Say you have a class Restaurant with a name and likes value:
class Restaurant {
var name: String?
var likes: Int = 0
}
You initialize a bunch of Restaurant
objects, and put them in an array called dataSource
. Your table view data source methods will look like this:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataSource.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .Default, reuseIdentifier: "cell");
cell.textLabel?.text = dataSource[indexPath.row].name
return cell
}
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// This can be empty if you're not deleting any rows from the table with your edit actions
}
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
// First, create a share action with the number of likes
let shareAction = UITableViewRowAction(style: .Default, title: "\(self.dataSource[indexPath.row].likes)") { (action, indexPath) -> Void in
// In your closure, increment the number of likes for the restaurant, and slide the cell back over
self.dataSource[indexPath.row].likes++
self.tableView.setEditing(false, animated: true)
}
return [shareAction] // return your array of edit actions for your cell. In this case, we're only returning one action per row.
}
I'm not going to write a scrollable cell from scratch, since this question has a bunch of options you can use.
I was, however, intrigued by Andrew Carter's attempt to iterate through subviews to access the UIButton
in the edit action directly. Here is my attempt:
First, create a reference to the UITableViewCell
(or an array of cells), you wish to modify, for this example, I'll be using a single cell:
var cellRef: UITableViewCell?
// ...
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .Default, reuseIdentifier: "cell");
cell.textLabel?.text = dataSource[indexPath.row].name
cellRef = cell;
return cell
}
In your share action, iterate through the button's subviews. We're looking for the UITableViewCellDeleteConfirmationView
and _UITableViewCellActionButton
objects (private headers linked for reference).
let shareAction = UITableViewRowAction(style: .Default, title: "\(self.dataSource[indexPath.row].likes)") { (action, indexPath) -> Void in
var deleteConfirmationView: UIView? // UITableViewCellDeleteConfirmationView
if let subviews = self.cellRef?.subviews {
for subview in subviews {
if NSClassFromString("UITableViewCellDeleteConfirmationView") != nil {
if subview.isKindOfClass(NSClassFromString("UITableViewCellDeleteConfirmationView")!) {
deleteConfirmationView = subview
break
}
}
}
}
if let unwrappedDeleteView = deleteConfirmationView {
if unwrappedDeleteView.respondsToSelector("_actionButtons") {
let actionbuttons = unwrappedDeleteView.valueForKey("_actionButtons") as? [AnyObject]
if let actionButton = actionbuttons?.first as? UIButton { // _UITableViewCellActionButton
actionButton.setTitle("newText", forState: .Normal)
}
}
}
}
Upvotes: 3
Reputation: 7841
This answer uses private API and it's NOT recommended to be used on the App Store. Apparently there is no way to change the title
of the native UITableViewRowAction
. You may have to implement your custom solution as suggested by others to achieve the result you want.
Here I'm traversing the subviews of UITableViewCell
which contains private subviews and are subject to change so your code may crash on future iOS releases if Apple changes the view hierarchy.
I found the header of UIButtonLabel
here.
The current view hierarchy as per iOS 9.2 is
UITableViewCell
UITableViewCellDeleteConfirmationView
_UITableViewCellActionButton
UIButtonLabel
UIButton
Here is the code:
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let shareAction = UITableViewRowAction(style: .Default, title: "\(dataList[indexPath.row].likes)") { (action, indexPath) -> Void in
self.dataList[indexPath.row].likes++
let cell = tableView.cellForRowAtIndexPath(indexPath)
let privateView = cell!.subviews[0].subviews[0].subviews[0]
let privateButton = privateView.valueForKey("_button") as! UIButton
privateButton.setTitle("\(self.dataList[indexPath.row].likes)", forState: .Normal)
}
return [shareAction]
}
Upvotes: 3
Reputation:
@JAL is totally right- you need to make your own sliding view to accomplish this, or be ok with reloading the cell and having it updated on the next slide out. Just for fun I tried to hack my way through the subviews and find the label and was able to find it, but what's funny is Apple has somehow blocked any changes being made to the text of that label. You can change it's background color / other properties but not the text!
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
return cell
}
func findRowActionLabelForCell(cell: UITableViewCell?) -> UILabel? {
guard let cell = cell else {
return nil
}
var label: UILabel? = nil
for view in cell.subviews {
label = findRowActionLabelForView(view)
if label != nil {
break
}
}
return label
}
func findRowActionLabelForView(view: UIView) -> UILabel? {
for subview in view.subviews {
if let label = subview as? UILabel {
return label
} else {
return findRowActionLabelForView(subview)
}
}
return nil
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let action = UITableViewRowAction(style: .Default, title: "Test", handler: { (action, indexPath) -> Void in
let cell = self.tableView.cellForRowAtIndexPath(indexPath)
if let label = self.findRowActionLabelForCell(cell) {
label.text = "New Value"
label.backgroundColor = UIColor.blueColor()
}
})
return [action]
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
}
}
Upvotes: 2