I'm trying to add image in UITableView Swipe style. I tried with Emoji text & its working fine
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let editAction = UITableViewRowAction(style: .normal, title: "🖋") { (rowAction, indexPath) in
print("edit clicked")
}
return [editAction]
}
But I need image instead of Emoji, meanwhile I tried
editAction.backgroundColor = UIColor.init(patternImage: UIImage(named: "edit")!)
But it's getting duplicate image, I used images in many format like 20*20, 25*25, 50*50 but still duplicating.
How can I add image?
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
I had the same problem with my project, so I did a workaround for this.
I think, this is helpful for you.
When I swipe table cell to the left only for image width, it is working fine.
But when I swipe table cell more than image width, table cell display like this:
This happen because to add image I use 'backgroundColor' property.
copyButton.backgroundColor = UIColor(patternImage: UIImage(named: "bfaCopyIcon.png")!)
So to fix this, I increase image width to the same as table width.
old image >>>>>>>>>>>> new image
>>>>
this is the new look:
This is my sample code:
func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? {
let copyButton = UITableViewRowAction(style: .normal, title: "") { action, index in
print("copy button tapped")
}
copyButton.backgroundColor = UIColor(patternImage: UIImage(named: "bfaCopyIcon.png")!)
let accessButton = UITableViewRowAction(style: .normal, title: "") { action, index in
print("Access button tapped")
}
accessButton.backgroundColor = UIColor(patternImage: UIImage(named: "bfaAccess.png")!)
return [accessButton, copyButton]
}
I came across this same problem and discovered a really good pod for this called SwipeCellKit that makes it really easy to implement an image into your swipe cell action without the swipe action causing multiple images to show. it also allows for more customization such as different swipe directions.
Steps:
add pod
import SwipeCellKit
make cell conform to SwipeTableViewCell
in cellForRow function set the cells delegate to self
follow the implementation below or via the link
link to pod -> https://github.com/SwipeCellKit/SwipeCellKit
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
// handle action by updating model with deletion
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete")
return [deleteAction]
}
func tableView(_ tableView: UITableView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
var options = SwipeOptions()
options.expansionStyle = .destructive
return options
}
I found one way of doing this in SWIFT 3 -
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
//let cell = tableView.cellForRow(at: indexPath)
//print(cell?.frame.size.height ?? 0.0)//hence we need this height of image in points. make sure your contentview of image is smaller
let deleteAction = UITableViewRowAction(style: .normal, title:" ") { (rowAction, indexPath) in
print("delete clicked")
}
deleteAction.backgroundColor = UIColor(patternImage:UIImage(named: "delete")!)
return [deleteAction]
}
We need to make sure our image dimension is matching with cell row height
Here is my image which i used
Here is how I do it in objective-c and should work in swift when translated.
- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *deleteString = #"Delete";
CGFloat tableViewCellHeight = [self tableView:tableView heightForRowAtIndexPath:indexPath];
UIImage *image = [UIImage imageNamed:#"delete_icon"];
CGFloat fittingMultiplier = 0.4f;
CGFloat iOS8PlusFontSize = 18.0f;
CGFloat underImageFontSize = 13.0f;
CGFloat marginHorizontaliOS8Plus = 15.0f;
CGFloat marginVerticalBetweenTextAndImage = 3.0f;
float titleMultiplier = fittingMultiplier;
NSString *titleSpaceString= [#"" stringByPaddingToLength:[deleteString length]*titleMultiplier withString:#"\u3000" startingAtIndex:0];
UITableViewRowAction *rowAction= [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:titleSpaceString handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
//Do Stuff
}];
CGSize frameGuess=CGSizeMake((marginHorizontaliOS8Plus*2)+[titleSpaceString boundingRectWithSize:CGSizeMake(MAXFLOAT, tableViewCellHeight) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName: [UIFont systemFontOfSize:iOS8PlusFontSize] } context:nil].size.width, tableViewCellHeight);
CGSize tripleFrame=CGSizeMake(frameGuess.width*3.0f, frameGuess.height*3.0f);
UIGraphicsBeginImageContextWithOptions(tripleFrame, YES, [[UIScreen mainScreen] scale]);
CGContextRef context=UIGraphicsGetCurrentContext();
[[UIColor blueColor] set];
CGContextFillRect(context, CGRectMake(0, 0, tripleFrame.width, tripleFrame.height));
CGSize drawnTextSize=[deleteString boundingRectWithSize:CGSizeMake(MAXFLOAT, tableViewCellHeight) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName: [UIFont systemFontOfSize:underImageFontSize] } context:nil].size;
[image drawAtPoint:CGPointMake((frameGuess.width/2.0f)-([image size].width/2.0f), (frameGuess.height/2.0f)-[image size].height-(marginVerticalBetweenTextAndImage/2.0f)+2.0f)];
[deleteString drawInRect:CGRectMake(((frameGuess.width/2.0f)-(drawnTextSize.width/2.0f))*([[UIApplication sharedApplication] userInterfaceLayoutDirection]==UIUserInterfaceLayoutDirectionRightToLeft ? -1 : 1), (frameGuess.height/2.0f)+(marginVerticalBetweenTextAndImage/2.0f)+2.0f, frameGuess.width, frameGuess.height) withAttributes:#{ NSFontAttributeName: [UIFont systemFontOfSize:underImageFontSize], NSForegroundColorAttributeName: [UIColor whiteColor] }];
[rowAction setBackgroundColor:[UIColor colorWithPatternImage:UIGraphicsGetImageFromCurrentImageContext()]];
UIGraphicsEndImageContext();
return #[rowAction];
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let write = UITableViewRowAction(style: .default, title: "\u{1F58A}") { action, index in
print("edit button tapped")
}
return [write]
}
try this used unicode instead icon. this will work
Related
I have a UITableView that has a different row height for the last column.
Each row has UIContextualAction to "mark as favourite" and "delete", represented by image (icons). It seams that when the row height is smaller then 50, the UIContextualAction.image placement is corrupted and no longer centered correctly:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let (training, package) = decodeIndexPath(indexPath)
return package?.trainings.last == training ? 50 : 49
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
guard let training = decodeIndexPath(indexPath).0 else { return nil }
let imageSizeAction = CGSize(width: 30, height: 30)
var actions = [UIContextualAction]()
//add delete action (only custom exercises)
if training.isCustom {
let deleteAction = UIContextualAction(style: .destructive, title: nil) { [weak self] (action, view, completion) in
guard let training = self?.decodeIndexPath(indexPath).0 else { return }
Database.shared.deleteCustom(training: training, completion: logAsError)
completion(true)
}
deleteAction.image = PaintCode.imageOfBtnCellActionDelete(imageSize: imageSizeAction)
actions.append(deleteAction)
}
//add to favorites
let favoriteAction = UIContextualAction(style: .normal, title: nil) { [weak self] (action, view, completion) in
guard var training = self?.decodeIndexPath(indexPath).0 else { return }
training.isFavorite = !training.isFavorite
tableView.isEditing = false
completion(true)
}
favoriteAction.backgroundColor = PaintCode.mainBlue
let image = PaintCode.imageOfBtnCellActionFavorite(imageSize: imageSizeAction, selected: training.isFavorite)
favoriteAction.image = image
actions.append(favoriteAction)
let action = UISwipeActionsConfiguration(actions: actions)
//only allow full swipe if delete is added
action.performsFirstActionWithFullSwipe = actions.contains(where: {$0.style == .destructive})
return action
}
I tried using the backgroundColor and making a patternImage color I am able to get it centred correctly, however because of the tiling action you then get the icon repeated when you stretch the swipe. Not the wanted behaviour
favoriteAction.backgroundColor = UIColor(patternImage: PaintCode.imageOfBtnCellActionFavorite(imageSize:imageSize, selected: training.isFavorite))
So I see no other option then to have a min height of 50 points to make everything work reliably.
Evening ladies and gentleman,
I am currently getting used to Swift and wanted to start with a little todo app. So far I can add an item and safe it persistently in a context. When an item has been added, it will be shown in a tableview. Now, I want to use a check swipe to strikethrough items, which have been added and safe this information in my context. Deleting using a swipe works perfectly fine.
Has anybody an idea how realize this? I tried to solve it by myself, but couldnt get it done. A similar question has been asked here before, but didnt get a proper answer: Add strikethrough to tableview row with a swipe
func checkAccessoryType(cell: UITableViewCell, isCompleted: Bool) {
if isCompleted {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let todo = CoreDataManager.shared.getTodoItem(index: indexPath.row)
todo.completed = !todo.completed
CoreDataManager.shared.safeContext()
if let cell = tableView.cellForRow(at: indexPath){
checkAccessoryType(cell: cell, isCompleted: todo.completed)
}
}
Assuming you are trying to strikethrough the title of your task -- which should be defined as a label -- here is the approach to take:
1- Make sure your label is set to attributed text rather than plain. To do that, go to Main.storyboard, select your label, and inside the attribute inspector, set text to Attributed.
2- Inside your completion block (that is the completion block executed after a swipe) add the following code:
(SWIFT 5)
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: taskLabel.text)
attributeString.addAttribute(.strikethroughStyle, value: 1, range: NSRange(location: 0, length: taskLabel.text.count))
taskLabel.attributedText = attributeString
Just a little advice: it's always helpful if you add some code when you ask a question.
Let me know if anything doesn't make sense.
Looking at the link that you provided, you need swipe action on your UITableViewCell.
Try looking into:
leadingSwipeActionsConfigurationForRowAt
trailingSwipeActionsConfigurationForRowAt
You need this action to perform the strikethrough label or delete:
func tableView(_ tableView: UITableView,
leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let closeAction = UIContextualAction(style: .normal, title: "Close", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("OK, marked as Closed")
success(true)
})
closeAction.image = UIImage(named: "tick")
closeAction.backgroundColor = .purple
return UISwipeActionsConfiguration(actions: [closeAction])
}
func tableView(_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let modifyAction = UIContextualAction(style: .normal, title: "Update", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("Update action ...")
success(true)
})
modifyAction.image = UIImage(named: "hammer")
modifyAction.backgroundColor = .blue
return UISwipeActionsConfiguration(actions: [modifyAction])
}
Source: https://developerslogblog.wordpress.com/2017/06/28/ios-11-swipe-leftright-in-uitableviewcell/
I have a tableview dynamic prototype custom tableview cells.
My tableview cell color is white and the background of tableview is also white.
I want swipe to right delete feature for my tableviewcell, and with custom tableviewrowaction
I have implemented the same in my app with custom tableviewrowaction which is working fine but the only problem is when I swipe right the cell bounces and there is a gray background color behind the cell. I have removed the backgroundview, changed the color of cell and tableview but still when I swipe the cell , I can see the background color as gray.
Following is the code written to display the custom tableview delete row action
public func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction(style: .default, title: "") { (action, indexPath) in
let cell = self.tableview.cellForRow(at: indexPath) as? CardInfoSwipeCell
cell?.deleteAction(action)
}
deleteAction.setIcon(iconImage: UIImage(named: "delete")!, backColor: UIColor.white, cellHeight: 100.0, iconSizePercentage: 0.79)
return [deleteAction]
}
Following is the code to set the image on tableviewrowaction
extension UITableViewRowAction {
func setIcon(iconImage: UIImage, backColor: UIColor, cellHeight: CGFloat, iconSizePercentage: CGFloat)
{
let iconHeight = cellHeight * iconSizePercentage
let margin = (cellHeight - iconHeight) / 2 as CGFloat
UIGraphicsBeginImageContextWithOptions(CGSize(width: cellHeight, height: cellHeight), false, 0)
let context = UIGraphicsGetCurrentContext()
backColor.setFill()
context!.fill(CGRect(x:0, y:0, width:cellHeight, height:cellHeight))
iconImage.draw(in: CGRect(x: 0, y: margin, width: iconHeight - 10, height: iconHeight - 4))
let actionImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.backgroundColor = UIColor.init(patternImage: actionImage!)
}
}
Please find the attached screenshot where a gray background gets displayed behind
Is there any way to disable the tableview dragging bounce so that it should not be dragged beyond a certain point.
I tried setting the background color to .clear but that did not work. This workaround gets the job done.
action.backgroundColor = UIColor(white: 1, alpha: 0.001)
You could use this library https://github.com/SwipeCellKit/SwipeCellKit allows you to place icons on the UITableViewRowAction
[TableView] Setting a pattern color as backgroundColor of UITableViewRowAction is no longer supported.
To disable the tableview dragging bounce you can use the following method -
#available(iOS 11.0, *)
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, sourceView, completionHandler) in
// Code to perform delete action
completionHandler(true);
}
let swipeAction = UISwipeActionsConfiguration(actions:[delete])
swipeAction.performsFirstActionWithFullSwipe = false // This is the line which disables full swipe
return swipeAction
}
i am trying to add image in the UIContextualAction , see the code below:-
func tableView(_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
// Write action code for the Flag
let FlagAction = UIContextualAction(style: .normal, title: "View", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("Update action ...")
success(true)
})
FlagAction.image = UIImage(named: "flag")
return UISwipeActionsConfiguration(actions: [FlagAction])
}
The image , i am using
we can take size 30 by 30 , is the standard size , we can take more than 30 pixel , depending on the size of the screen.
Here is the image that is support
The UIContextualAction only accepts template image, which use different transparent degree to define the image's shape and color.
hi it is worked fine for me ,
That image size will auto adjust according to pixel of the image.
private func searchBarCode(forRowAt indexPath: IndexPath) -> UIContextualAction {
let context = UIContextualAction(style: .destructive, title: "") { (action, swipeButtonView, completion) in
completion(true)
}
context.backgroundColor = UIColor.white
context.image = UIImage(named: "document")
return context
}
Click here to see table view edit image
swipe table view cell then show some option to delete and edit. I want to set full image. I have seen lots of demo code but then are with text and background image, I have need to create with whole image here is my code for ios 10 and ios 11 but I cant get success
with editActionsForRowAt Problem is image is repeate multiple time
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
{
let ArchiveAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: " ") { (action , indexPath ) -> Void in
tableView.setEditing(false, animated: false)
}
let shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: " ") { (action , indexPath) -> Void in
tableView.setEditing(false, animated: false)
}
ArchiveAction.backgroundColor = UIColor(patternImage: UIImage(named: "archiver.png")!)
shareAction.backgroundColor = UIColor(patternImage: UIImage(named: "bloquear.png")!)
return [ArchiveAction,shareAction]
}
with trailingSwipeActionsConfigurationForRowAt Problem is image not show properly. show white image
#available(iOS 11.0, *)
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let action = UIContextualAction(style: .normal, title: "sdfsdf", handler: { (action,view,completionHandler ) in
//do stuff
completionHandler(true)
})
// action.image = UIImage(named: "archiver.png")
action.backgroundColor = .black
let confrigation = UISwipeActionsConfiguration(actions: [action])
confrigation.performsFirstActionWithFullSwipe = true // default is false
return confrigation
}
Please give me any solution
I also experienced the problem of a white rectangle instead of the image when using .jpg. Using a .png worked for me.
Since you are using a .png already, did you try to load the image name without the .png extension? ("archiver" instead of "archiver.png")
Because the parameter description of init?(named name: String) says:
... For PNG images, you may omit the filename extension. For all other file formats, always include the filename extension.