I'm using swipe to delete in UITableView. In swipe I need to add image. When I add image it repeats. How to stop repeating
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteButton = UITableViewRowAction(style: .default, title: "Delete") { (action, indexPath) in
self.tableView.dataSource?.tableView!(self.tableView, commit: .delete, forRowAt: indexPath)
return
}
deleteButton.backgroundColor = UIColor(patternImage: #imageLiteral(resourceName: "favourite_delete"))
deleteButton.title = ""
return [deleteButton]
}
Problem
What I need
The problem, as you might have guessed, is here:
deleteButton.backgroundColor = UIColor(patternImage: #imageLiteral(resourceName: "favourite_delete"))
You are creating a UIColor using the (patternImage:) initializer. This means that the image will be repeated (See the word "pattern"?).
From the docs:
You can use pattern colors to set the fill or stroke color just as you would a solid color. During drawing, the image in the pattern color is tiled as necessary to cover the given area.
To solve this, you can resize your image so that it fits the frame of the button programmatically. See The simplest way to resize an UIImage?
Alternatively, use MGSwipeTableViewCell, it allows you to put images on swipe buttons.
you can use resizeWithWidth():
let placeHolderImage = UIImage(systemName: "person.circle.fill")!.resizeWithWidth(width: 40)!
color = UIColor(patternImage: placeHolderImage)
Related
I am using Kingfisher to download and cache remote images.
I would like to render those images in a UITableViewCell
Currently the images do not show until I scroll.
I suspect this is because the initial image size is nil, once I scroll the cell is redrawn and the image is rendered.
To negate this issue I have called tableView.reloadRows(at: [indexPath], with: .none) in the completion handler of Kingfisher
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeedTableViewCellId", for: indexPath) as! FeedGifCell
let url = URL(string: items[indexPath.item])!
let imageView = ImageResource(downloadURL: url, cacheKey: "\(url)-imageview")
let placeHolderImage = UIImage.from(hex: "ffffff").resize(width: 1, height: 190)
cell.gifImage.kf.setImage(with: imageView, placeholder: placeHolderImage) { _ in
tableView.reloadRows(at: [indexPath], with: .none)
}
return cell
}
I have applied a simple placeholder of a fixed height and width to give the cell some height before the image is applied.
I am not sure this is the best approach, I do not like calling tableView.reloadRows(at: [indexPath], with: .none) this feels a little.....hacky.
Also, before the cell is redrawn I have the white space, my placeholder, then a jump as the correct image / size is applied.
Is it possible to simply prevent the cell from being visible at all until the image has been applied?
No! You don't have to reload the tableView in any way after the image in a certain cell gets done downloading. Other than that, you're doing everything correctly. I use Kingfisher too.
But in the future, you could just make a function in your cell class, say setupCell(_ imageURL: URL?). Anyways, going on, in your cellForRow method, just do it like this:
cell.gifImage.kf.setImage(with: imageView, placeholder: placeHolderImage, completionHandler: nil)
Now, in case that there's no image downloaded or you have no image URL string to be made to URL object, you could catch it in Kingfisher's error block, then you will need to pass your error image (a UIImage) object to your imageView so that there would be no duplicate image.
For example, I have the following in my cell's setupCell() function:
if let url = vendor.image?.URLEscaped {
let resource = ImageResource(downloadURL: url, cacheKey: url.absoluteString)
self.imageView_Vendor.kf.setImage(with: resource, options: [.transition(.fade(0.2)), .cacheOriginalImage])
return
}
self.imageView_Vendor.image = nil
I hope this helps!
EDIT:
For the handling of image height, this could help: https://stackoverflow.com/a/52787062/3231194
In the editing mode of UITableView, I need three things, the first two are easy to get using UITableView delegate methods:
Delete (- in red) button on the left of the row,
Reorder (three bars) row button on the right of the row,
A custom defined action (with title & background color) appearing on the left side of reorder (three bars) button.
How is it possible to get these three actions together?
Hi yes it is possible to make or add your own custom action by implementing the tableView delegate
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let archiveAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: " ") { (rowAct, index) in
}
let deleteAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: " ") { (rowAct, index) in
}
let archiveImg = UIImageView(image: UIImage(named: "archive_btn"))
archiveImg.contentMode = .scaleAspectFit
archiveAction.backgroundColor = UIColor(patternImage:archiveImg.image!)
let deleteImg = UIImageView(image: UIImage(named: "delete_btn"))
deleteImg.contentMode = .scaleAspectFit
deleteAction.backgroundColor = UIColor(patternImage:deleteImg.image!)
return [deleteAction,archiveAction]
}
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
I am trying to make a custom checkbox list using the UITableview that allows single selections (I should however be able to select as many options as I want) and a custom UITableCell.
My custom cell contains a Label and an ImageView and all I want is to change the image contained in the IV on tap.
I am able to change the image from unchecked to checked in my didSelectRowAtIndexPath without a problem but I am having problems changing it back from checked to unchecked.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
print("tableView -> didSelectRowAtIndexPath")
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! CustomCellVC
cell.backgroundColor = UIColor.clearColor()
cell.ivRiskCellImage.image = UIImage(named: "CheckedBox")
}
I tried to play with the highlighted state of the ImageView by adding the checkedbox image as the highlighted image and then turning it on and off but it only enters the if but ignores the if else if clicked again
if(cell.ivCellImage.highlighted == false)
{
print("Highligth is OFF")
cell.ivCellImage.highlighted = true
}
else if(cell.ivCellImage.highlighted == true)
{
print("Highligth is ON")
cell.ivCellImage.highlighted = false
}
as well as checking what image is inside the IV, this if-else block being completely ignored
if(cell.ivRiskCellImage.image!.isEqual(UIImage(named: "UncheckedBox")))
{
print("Is unchecked!")
cell.ivRiskCellImage.image = UIImage(named: "CheckedBox")
}
else if(cell.ivRiskCellImage.image!.isEqual(UIImage(named: "CheckedBox")))
{
print("Is checked!")
cell.ivRiskCellImage.image = UIImage(named: "UnheckedBox")
}
Moreover, when I manage to display the checkedbox image on click I get something like this
while if I try setting the checked box for all the cells in cellForRowAtIndexPath by adding this
cell.ivRiskCellImage.image = UIImage(named: "CheckedBox")
the checkbox tick is no longer semitransparent but white, as it should be
Any ideas? I spent quite some time trying to solve this without any luck.
Instead of let cell = tableView.dequeueReusableCellWithIdentifier... I would use
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomCellVC
This way you get a reference to the cell you want to change the image in. tableView.dequeueReusableCellWithIdentifier is meant to be used in delegate method tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) when you want to recycle your cells for better performance.
Also cell.ivRiskCellImage.image!.isEqual(UIImage(named: "UncheckedBox")) doesn't work, because UIImage(named: "UncheckedBox") creates a new UIImage, which isn't the same as the UIImage you want to check it against.
As fat i understand that you want to change image form Check and Uncheck and vice versa
There is mainly two methods of table view delegate
– tableView:didDeselectRowAtIndexPath:
– tableView:didSelectRowAtIndexPath:
reference link : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/#//apple_ref/occ/intfm/UITableViewDelegate/tableView:didDeselectRowAtIndexPath:
Although you can do same thing in – tableView:didDeselectRowAtIndexPath:
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
{
print("tableView -> didSelectRowAtIndexPath")
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! CustomCellVC
cell.backgroundColor = UIColor.clearColor()
cell.ivRiskCellImage.image = UIImage(named: "**unCheckedBox**")
}