Uitableviewrowaction Title as Image Icon Instead of Text

UITableViewRowAction with icon and text

What I ended up doing was generating an image on the fly as the background. This required the use of a hack/clever-trick or two.

The first part is the standard delegate method:

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

let stockWidth = String(repeating: " ", count: 8)
let rename = UITableViewRowAction(style: .normal, title: stockWidth) { (_, indexPath) in
self.renameEntry(indexPath)
}
self.fixAction(rename, text: "Rename", image: UIImage(named: "pencilEdit")!, color: UIColor(52, 61, 70))
let locate = UITableViewRowAction(style: .normal, title: stockWidth) { (_, indexPath) in
self.locateEntry(indexPath)
}
self.fixAction(locate, text: "Locate", image: UIImage(named: "locatePin")!, color: UIColor(38, 107, 215))
let delete = UITableViewRowAction(style: .normal, title: stockWidth) { (_, indexPath) in
self.deleteEntry(indexPath)
}
self.fixAction(delete, text: "Forget", image: UIImage(named: "triggerDeleteSelector")!, color: UIColor(227, 34, 60))
let gap = UITableViewRowAction(style: .normal, title: "") { (_, _) in
// pass
}
gap.backgroundColor = UIColor.clear
return [gap, delete, locate, rename]
}

There's two not obvious details there. First, the action derives its width from the text string passed in. If you didn't give it some width via some non-visible space characters, the background image wouldn't have any area to be drawn in. That's the reason for the stockWidth string used in the first 3 actions. It's 8 character width is shared by the fixAction method that generates the background image.

The second detail is the inclusion of the fourth "gap" action at the bottom. For some reason, if the first action has a background paint that is a tile pattern, it will stretch left under the other actions. I found that I had to insert this zero width no op action at the front to avoid that.

func fixAction(_ action:UITableViewRowAction, text:String, image:UIImage, color:UIColor) {
// make sure the image is a mask that we can color with the passed color
let mask = image.withRenderingMode(.alwaysTemplate)
// compute the anticipated width of that non empty string
let stockSize = action.title!.sizeWithAttributes([NSFontAttributeName: UIFont.systemFont(ofSize: 18)])
// I know my row height
let height:CGFloat = 70
// Standard action width computation seems to add 15px on either side of the text
let width = (stockSize.width + 30).ceiling
let actionSize = CGSize(width: width, height: height)
// lets draw an image of actionSize
UIGraphicsBeginImageContextWithOptions(actionSize, false, 0.0)
if let context = UIGraphicsGetCurrentContext() {
context.clear(CGRect(origin: .zero, size: actionSize))
}
color.set()
let attributes = [NSForegroundColorAttributeName: color, NSFontAttributeName: UIFont(name: "Avenir-Book", size: 13)]
let textSize = text.size(attributes: attributes)
// implementation of `half` extension left up to the student
let textPoint = CGPoint(x: (width - textSize.width).half, y: (height - (textSize.height * 3)).half + (textSize.height * 2))
text.draw(at: textPoint, withAttributes: attributes)
let maskHeight = textSize.height * 2
let maskRect = CGRect(x: (width - maskHeight).half, y: textPoint.y - maskHeight, width: maskHeight, height: maskHeight)
mask.draw(in: maskRect)
if let result = UIGraphicsGetImageFromCurrentImageContext() {
// adjust the passed in action's backgroundColor to a patternImage
action.backgroundColor = UIColor(patternImage: result)
}
else {
"WTH!!!".logError()
}
UIGraphicsEndImageContext()
}

UITableViewRowAction image for title

iOS 11.0

Swift

Apple introduced flexible way to declare row actions with great benefits.

extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let askAction = UIContextualAction(style: .normal, title: nil) { action, view, complete in
print("Ask!")
complete(true)
}

// here set your image and background color
askAction.image = IMAGE
askAction.backgroundColor = .darkGray

let blockAction = UIContextualAction(style: .destructive, title: "Block") { action, view, complete in
print("Block")
complete(true)
}

return UISwipeActionsConfiguration(actions: [blockAction, askAction])
}

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.textLabel?.text = "row: \(indexPath.row)"
}
}

Example:

Sample Image

iOS 8.0

You need to set UIImage to backgroundColor of row action, concretely by:

Swift:

UIColor(patternImage: UIImage(named: "IMAGE_NAME"))

Objective-C:

[UIColor colorWithPatternImage:[UIImage imageNamed:@"IMAGE_NAME"]];

How to add image in UITableViewRowAction?

Finally in iOS 11, SWIFT 4 We can add add image in UITableView's swipe action with help of UISwipeActionsConfiguration

@available(iOS 11.0, *)
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {

let action = UIContextualAction(style: .normal, title: "Files", handler: { (action,view,completionHandler ) in
//do stuff
completionHandler(true)
})
action.image = UIImage(named: "apple.png")
action.backgroundColor = .red
let configuration = UISwipeActionsConfiguration(actions: [action])

return configuration
}

Sample Image

WWDC video at 28.34

Apple Doc

Note: I have used 50*50 points apple.png image with 50 tableview row height

Add Image To Button In UITableView's editActionsForRowAt

One of the comments lead me to using unicode characters! Super helpful as they can be added to your normal string. Unicode characters include things like:

Useful unicode character examples
Useful unicode character examples 2
Useful unicode character examples 3

So all you do is pass a string with a unicode character, then a line break (\n), then your button title/text. So the basic syntax looks like:

title: "\u{1234}\n YourText "

For easy reuse (because I have multiple tables) I put the characters I wanted into a struct:

struct cellEditActionIcons {
static var editAction_Arrow = "\u{2191}"
static var editAction_Check = "\u{2713}"
static var editAction_Delete = "\u{2715}"
}

Then you can create the buttons like this:

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
var doneBut = UITableViewRowAction (style: .normal, title: "\(cellEditActionIcons.editAction_Check)\n YourText" { action, index in
//Do stuff
}
doneBut.backgroundColor = myColors.someColor
}

How to set the title for the icon at the bottom on swipe right?

Just an example. You can replace the icon and title by yours. But this is how you should do this. Use centerIconOverText function in the library:

let mail = MGSwipeButton(title: "Mail", icon: UIImage(named: "mail.png"), backgroundColor: UIColor.blue)
mail.centerIconOverText()

Here is the output :

Sample Image

UIContextualAction icon and text alignment

It doesn't appear there is an answer to why the text appears, and appears mis-aligned.

For anyone who comes across this question, we ended up setting the titles to nil for these buttons to keep them "icon only".

How to show image when triggering UITableViewRowAction?

I think it's time to upgrade to these ios 11 new methods with image property

public func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
public func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?

So try this

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .normal, title: "", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
// Call edit action

// Reset state
success(true)
})
deleteAction.image = UIImage(named: "icon_trash")
deleteAction.backgroundColor = .red
return UISwipeActionsConfiguration(actions: [deleteAction])
}


Related Topics



Leave a reply



Submit