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:
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"]];
UISwipeActionsConfiguration/UIContextualAction with icon AND text AND clear background
Use patternImage to set the background color and don't set the title or image. This is a hacky trick but it should work for your situation.
let rename = UIContextualAction(style: .normal, title: nil) { (_, view, _) in
self.renameEntry(indexPath)
}
rename.backgroundColor = UIColor(patternImage: UIImage(named: "pencilEditWideFrame")!)
You have to save your images with wide frames like this with the icon at the far left so they don't actually repeat:
Note: I tested this and it works when using two or more contextual actions but doesn't work with just one. The pattern ends up repeating on a full swipe.
This also assumes that you have a plain background behind your tableview that you can use for the background color of the image as transparency is still a no-go.
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
}
WWDC video at 28.34
Apple Doc
Note: I have used 50*50 points apple.png image with 50 tableview
row height
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".
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:
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
}
Related Topics
Swift: Uicollectionview Selecting Cell Indexpath Issues
Subclassing VS Extension in Swift
Detect Ethernet/Wifi Network Change
Swift Struct Doesn't Conform to Protocol Equatable
How to Set Inputview for Textfield in Swiftui
How to Rounded the Corners When I Draw Rectangle Using Uibezierpath Points
Format String with Trailing Zeros Removed for X Decimal Places in Swift
Handling Network Error in Combination with Binding to Tableview (Moya, Rxswift, Rxcocoa)
How to Use Environment Map in Arkit
Is Code Coverage Already Working for Swift
How to Recognize Continuous Touch in Swift
Pop to Root View Using Tab Bar in Swiftui
Swift Only -- Reading from Nsinputstream
What Is Import Func, Struct, Class, and @_Exported in Swift
Update Core Data Object Order - Not Working
Swiftui @Environmentobject Error: May Be Missing as an Ancestor of This View
Xcode 10 Beta 5 - Clang: Error: Linker Command Failed with Exit Code 1