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"]];
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
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()
}
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
}
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])
}
UITableViewRowAction with image instead of title
Yes, this is an image size problem.
Even I had a similar requirement and faced the same problem. In this case when you use,
action.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"remove"]];
Even if you set the imageView.contentMode to:
UIViewContentModeScaleAspectFit
UIViewContentModeScaleToFill
UIViewContentModeScaleAspectFill
If the size of the image you are using and and the size of the button on the cell do not match, the image will not stretch to fill the entire button, rather the image pattern will just repeat itself until the entire area of the button is utilised.
This is because you are setting the 'backgroundColor' and not the actual 'backgroundImage'. 'backgroundColor' unlike 'backgroundImage' does not adhere to UIContentMode of the button.
Hence, what you will have to do is, create a image which is exactly equal to the size of the button. Doing this is not possible if your cell has a dynamic height (height determined at runtime according to your content).
Trying to set a button with an image in tableView:editActionsForRowAt:
This is one of the way. You have to create image with UIGraphicsBeginImageContextWithOptions
.
func swipeCellButtons() -> UIImage
{
let commonWid : CGFloat = 40
let commonHei : CGFloat = 70 // EACH ROW HEIGHT
var img: UIImage = UIImage(named: "pause") // TRY IMAGE COLOR WHITE
UIGraphicsBeginImageContextWithOptions(CGSize(width: commonWid, height: commonHei), false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(UIColor.clear.cgColor)
context!.fill(CGRect(x: 0, y: 0, width: commonWid, height: commonHei))
var img: UIImage = UIImage(named: "pause")!
img.draw(in: CGRect(x: 5, y: 15, width: 30, height: 30))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
func tableView(_ tableView: UITableView,
editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let myButton = UITableViewRowAction(style: .normal, title: "") {
action, index in
print("myButton was tapped")
}
let patternImg = swipeCellButtons()
myButton.backgroundColor = UIColor(patternImage: patternImg)
return [myButton]
}
Related Topics
Looping Through Nsattributedstring Attributes to Increase Font Size
Autolayout Link Two Uilabels to Have the Same Font Size
Xcode 6 Keeps Renaming My App's Directory in iOS8 Simulator After Each Run
-Canopenurl: Failed for Url: "Fbauth2:/" (Osstatus Error -10814.)"
Firebase Cloud Messaging - Send Message to All Users
Passing Parameters to a Method Called by Nstimer in Swift
Handling Push Notifications When App Is Terminated
Convert an iOS Objective C Object to a JSON String
How to Get Image Metadata in iOS
Color All Occurrences of String in Swift
Resize Textfield Based on Content
Test Whether a Uiview Is in the Middle of Animation
Avcapturesession and Background Audio iOS 7
403 Error - Thats an Error. Error: Disallowed_Useragent
Swift - Download a Video from Distant Url and Save It in an Photo Album