I have a trailingSwipeAction in a UITableViewCell, whose background color must be clear.
This is the code where I set the action :
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let myAction = UIContextualAction.init(style: .normal, title: nil) {
// My action code
}
myAction.backgroundColor = .clear
myAction.image = UIImage.init(named: "my-icon")
return UISwipeActionsConfiguration.init(actions: [myAction])
}
But I am getting gray background for the action, when no color was expected:
You can just set the alpha value to 0 for background color of the action:
let modifyAction = UIContextualAction(style: .normal, title: "", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("Update action ...")
success(true)
})
modifyAction.backgroundColor = UIColor.init(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 0.0)
You'll have to access the UIView inside the UIActionStandardButton inside the UISwipeActionPullView. and then change its background color.
You can see the view hierarchy of your app swiping on a cell, then going the Debug menu in Xcode, then View Debugging, and choose Capture View Hierarchy.
First of all, let add this useful extension that gets all subviews and their subviews in an array:
extension UIView {
var allSubViews : [UIView] {
var array = [self.subviews].flatMap {$0}
array.forEach { array.append(contentsOf: $0.allSubViews) }
return array
}
}
And then in viewWillLayoutSubviews():
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let btn = tableView
.allSubViews //get all the subviews
.first(where: {String(describing:type(of: $0)) == "UISwipeActionStandardButton"}) // get the first one that is a UISwipeActionStandardButton
//This UISwipeActionStandardButton has two subviews, I'm getting the one that is not a UILabel, in your case, since you've set the image, you should get the one that is not an imageView
if let view = btn?.subviews.first(where: { !($0 is UILabel)})
{
view.backgroundColor = .clear //Change the background color of the gray uiview
}
}
I am using viewWillLayoutSubviews() since it's called to notify the view controller that its view is about to layout its subviews. Have a look here for more details.
This solution is optimized for one swipe action button. If you have more than one button, the code would look like this:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let buttons = tableView
.allSubViews //get all the subviews
.filter {String(describing:type(of: $0)) == "UISwipeActionStandardButton"}
buttons.forEach { btn in
if let view = btn.subviews.first(where: { !($0 is UIImageView)}) //If you're sure that other than the uiview there is a UIImageView in the subviews of the UISwipeActionStandardButton
{
view.backgroundColor = .clear //Change the background color of the gray uiview
}
}
}
Apparently if you set the background color to white with zero alpha, it will stay clear but without the gray default color.
Try this:
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let deleteAction = UIContextualAction(style: .destructive, title: nil) { [weak self] (action, view, completion) in
// weak self to prevent memory leak if needed
guard let self = self else { return }
// do your nasty stuff here
completion(true)
}
deleteAction.backgroundColor = UIColor(white: 1, alpha: 0)
deleteAction.image = UIImage(systemName: "trash")
return UISwipeActionsConfiguration(actions: [deleteAction])
}
SOLUTION
Thanks to Carpsen90
You have to set the backgroundColor of that UIImageView to .clear, but it doesn't exist in the time of viewWillLayoutSubviews. It is created after you swipe.
A posible solution is to have a Timer:
var timerCellSwipeButtons: Timer?
Launched when the swipe is done:
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let editAction = UIContextualAction.init(style: .normal, title: nil) { [weak self] (action, view, completion) in
// editAction code
}
let deleteAction = UIContextualAction.init(style: .normal, title: nil) { [weak self] (action, view, completion) in
// deleteAction code
}
// Set the button's images
editAction.image = UIImage.init(named: "editIcon")
deleteAction.image = UIImage.init(named: "deleteIcon")
// You also must set the background color of the actions to .clear
editAction.backgroundColor = .clear
deleteAction.backgroundColor = .clear
// Launch the timer, that will run a function every 10 milliseconds
self.timerCellSwipeButtons = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerCellSwipeButtonsFunction), userInfo: nil, repeats: true)
// Return the actions
return UISwipeActionsConfiguration.init(actions: [deleteAction, editAction])
}
Now every 10 milliseconds (you can increase the frequency if you want), this function checks the tableView subviews looking for all the UISwipeActionStandardButton and setting to .clear the backgroundColor of their UIView:
#objc func timerCellSwipeButtonsFunction() {
// Gets all the buttons, maybe we have more than one in a row
let buttons = tableView.allSubViews.filter { (view) -> Bool in
String(describing: type(of: view)) == "UISwipeActionStandardButton"
}
// Loops through all the buttons
for button in buttons {
if let view = button.subviews.first(where: { !($0 is UIImageView)})
{
// We are interested in the UIView that isn't a UIImageView
view.backgroundColor = .clear
}
}
// When finish, timer is invalidated because we don't need it anymore.
// A new one will be launched with every swipe
self.timerCellSwipeButtons?.invalidate()
}
To get all the subviews of a UIView, I used the function given by Carpsen90:
extension UIView {
var allSubViews : [UIView] {
var array = [self.subviews].flatMap {$0}
array.forEach { array.append(contentsOf: $0.allSubViews) }
return array
}
}
For safety reasons, you should also invalidate the timer in the viewWillDisappear method:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.timerCellSwipeButtons?.invalidate()
}
And this is the result:
But as you can see, when you have more than one action in the same side of the cell and you swipe completely, doesn't look very nice:
To avoid icons overlapping I put only one action in each side:
// Remember to launch the timer in both swipe functions, like in the example above
// Function to add actions to the leading side of the cell
tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
// Function to add actions to the trailing side of the cell
tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
100% working in iOS swift for change swipe button image color and background color change.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
if isInbox {
let action = UIContextualAction(style: .normal, title: "", handler: { (action,view,completionHandler ) in
self.selectedIndex = indexPath.row
self.deleteNotification()
completionHandler(true)
})
let cgImageX = UIImage(named: "delete-1")?.cgImage
action.image = OriginalImageRender(cgImage: cgImageX!)
action.backgroundColor = UIColor.init(hex: "F7F7F7")
let confrigation = UISwipeActionsConfiguration(actions: [action])
return confrigation
}
return nil
}
Add this Class also for original image color display otherwise its showing only white image
class OriginalImageRender: UIImage {
override func withRenderingMode(_ renderingMode: UIImage.RenderingMode) -> UIImage {
return self
}
}
Following the solution from #Maulik Patel I just added a tint color option to the action.image:
let imageDelete = UIImage(systemName: "trash")?.cgImage
deleteAction.image = OriginalImageRender(cgImage: imageDelete!).withTintColor(UIColor(named: ("colorButton"))!)
deleteAction.backgroundColor = UIColor.init(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 0.0)
let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
return configuration
What I have done in my project is
func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {
let subViews = tableView.subviews.filter { (view) -> Bool in
if NSStringFromClass(view.classForCoder) == "UISwipeActionPullView" {
return true
}
return false
}
if subViews.count > 0 {
let bgView = subViews[0]
bgView.backgroundColor = bgColor
}
}
And my project's target is iOS 9.0 and above
Related
I am using swift 4.2 and xcode 10.1. I am working on a project and Created some fancy expand/Collapsable UITableView.
Everything is working just fine and awesome. Then there comes some need of introducing some swipe actions. So it looks so easy to create them here is how I am using and creating them
#available(iOS 11.0, *)
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let deleteAction = UIContextualAction(style: .destructive, title: "Add") { (action, view, handler) in
print("Add Action Tapped")
}
deleteAction.backgroundColor = .green
let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
return configuration
}
#available(iOS 11.0, *)
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { (action, view, handler) in
print("Delete Action Tapped")
}
deleteAction.backgroundColor = .red
let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
return configuration
}
But that is not working on my sections. The row gets swipable actions when I swipe them left or right. but No on my section headers. Here is how I am creating view for my section header.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = Bundle.main.loadNibNamed("HeaderCell", owner: self, options: nil)?.first as! HeaderCell
let shoppingList = mDataSource[section]
let itemCount = shoppingList.ShoppingItems.count
let txtStoreName = shoppingList.Store.P_FriendlyName! + " (\(itemCount))"
cell.lblName.text = txtStoreName
let imageHollow = UIImage(named: "checkbox_hollow") // For List Item Check box image
cell.btnSelectHeader.setImage(imageHollow, for: .normal)
if(shoppingList.IsSelected){
let imageChecked = UIImage(named: "checkbox_checked") // For List Item Check box image
cell.btnSelectHeader.setImage(imageChecked, for: .normal)
}
if(shoppingList.IsExpanded){
let image = UIImage(named: "ic-indicator-up")
cell.ivIndicatorExpandCollapse.image = image
cell.viewContentView.backgroundColor = CommonUtils.hexStringToUIColor(hex: AppColors.colorItemSelector)
}else{
let image = UIImage(named: "ic-indicator-down")
cell.ivIndicatorExpandCollapse.image = image
cell.viewContentView.backgroundColor = CommonUtils.hexStringToUIColor(hex: AppColors.colorWhite)
}
cell.backgroundView?.backgroundColor = UIColor.white
cell.isCellSwipable = IS_CELL_RIGHT_SWIPEABLE
cell.delegateHeader = self
cell.clickedSection = IndexPath.init(row: 0, section: section)
cell.clickedModel = shoppingList
return cell
}
Problems: here are my problems and questions
Section headers are not showing swipe actions as other cells are showing.
Are these swipe actions are available from iOS 11.0 up to latest or it will only work on iOS 11 only?
Please help me I am not sure why it is not working on section headers????
As of now, iOS does not allow to swipe section headers. I would like to recommend use your own logic. You can manage by changing view constraints (default view or swiped view) yourself for section header.
func sectionSwiped(gestureRecognizer: UITapGestureRecognizer) {
if let viewSwiped = gestureRecognizer.view as? UIView{
swipedSection = viewSwiped.tag
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let vw = UIView()
vw.tag = section
//You can customize view
var swipeRight = UISwipeGestureRecognizer(target: self, action: "sectionSwiped:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Right
vw.addGestureRecognizer(swipeRight)
return vw
}
Recently implemented trailingSwipeActionsConfigurationForRowAt , where after swiping from right to left showing two options and its working fine. But the problem is when i select multiple rows or single row, after swiping the row/s they are getting deselected. Is there a way to keep the selection even after swiping?
Below is my code
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let renameAction = contextualToggleRenameAction(forRowAtIndexPath: indexPath)
let lastResAction = contextualToggleLastResponseAction(forRowAtIndexPath: indexPath)
let swipeConfig = UISwipeActionsConfiguration(actions: [renameAction, lastResAction])
swipeConfig.performsFirstActionWithFullSwipe = false
return swipeConfig
}
func contextualToggleLastResponseAction(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction {
let sensorData = sensorsList?[indexPath.row]
var lastResponse = ""
if sensorData != nil{
if let lstRes = sensorData!["last_response"] as? String{
lastResponse = lstRes
}
}
let action = UIContextualAction(style: .normal, title: lastResponse) { (contextAction: UIContextualAction, sourceView: UIView, completionHandler: (Bool) -> Void) in
print("Last Response Action")
}
action.backgroundColor = UIColor(red: 61/255, green: 108/255, blue: 169/255, alpha: 1.0)
return action
}
Holy crap, I fixed this stupid issue.
Yes, yes make sure tableView.allowsSelectionDuringEditing = true and tableView.allowsMultipleSelectionDuringEditing = true.
But...
Shout-out to this SO answer which almost directly led me on the way to success (see here).
KEY: Re-select/de-select the rows in your implementation of setEditing, which is a method you override. UITableView goes into editing mode when swiping.
IMPORTANT NOTE: Call super.setEditing(...) before any of your code, as shown below, or it likely won't work, or at least not perfectly.
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
for i in 0..<your data.count {
if this item is selected {
self.tableView.selectRow(at: IndexPath(row: i, section: 0), animated: false, scrollPosition: .none)
} else {
self.tableView.deselectRow(at: IndexPath(row: i, section: 0), animated: false)
}
}
}
A swipe is considered as an edit, so you can enable allowsSelectionDuringEditing if you want to keep the selected state:
tableView.allowsSelectionDuringEditing = true
Depending on indexPathsForSelectedRows doesn't always give the expected result.
Instead you should maintain and array of selectedIndexPaths.
Here is a code snippet to demonstrate:
var selectedIndexPaths = [IndexPath]()
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedIndexPaths.contains(indexPath) {
selectedIndexPaths.removeAll { (ip) -> Bool in
return ip == indexPath
}else{
selectedIndexPaths.append(indexPath)
}
}
You can simply do this :
Create array in your controller for selected index
var arrSelectedIndex : [Int] = []
In didSelect,
if arrSelectedIndex.contains(indexPath.row) { // Check index is selected or not
// If index selected, remove index from array
let aIndex = arrSelectedIndex.firstIndex(of: indexPath.row)
arrSelectedIndex.remove(at: aIndex!)
}
else {
// If index not selected, add index to array
arrSelectedIndex.append(indexPath.row)
}
// reload selected row, or reloadData()
self.tblView.reloadRows([indexPath.row], with: .automatic)
Edit
In trailingSwipeActionsConfigurationForRowAt,
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
if self.arrSelectedIndex.contains(indexPath.row) {
let action = UIContextualAction(style: .normal, title: "") { (action, view, handler) in
}
action.backgroundColor = .green
let configuration = UISwipeActionsConfiguration(actions: [])
configuration.performsFirstActionWithFullSwipe = false
return configuration
}
let action = UIContextualAction(style: .normal, title: "Selected") { (action, view, handler) in
}
action.backgroundColor = .green
let configuration = UISwipeActionsConfiguration(actions: [action])
configuration.performsFirstActionWithFullSwipe = false
return configuration
}
Output
When I create a new cell it will automatically mark
or when I marked the first one, I was creating multiple
Cell, there will be duplicates marked
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let itemCellIdentifier = "itemCell"
guard let itemCell = itemCardTableView.dequeueReusableCell(withIdentifier: itemCellIdentifier, for: indexPath) as? ItemCardTableViewCell else {
return UITableViewCell()
}
let itemCard = dataManager.items[indexPath.row]
itemCell.itemTitle.text = itemCard.title
if itemCard.isFinish {
itemCell.itemCellView.backgroundColor = UIColor(red: 0, green: 123, blue: 0)
}
return itemCell
}
Add cell method
let confirm = UIAlertAction(title: "確認", style: .default) { (action: UIAlertAction) in
guard let title = addAlert.textFields?.first?.text else { return }
let newItem = ItemCard(title: title, isFinish: false)
self.dataManager.items.append(newItem)
let indexPath = IndexPath(row: self.itemCardTableView.numberOfRows(inSection: 0), section: 0)
self.itemCardTableView.insertRows(at: [indexPath], with: .left)
When I create new data isFinish = false
How can I fix data duplication?
You should provide else case to set default background color.
if itemCard.isFinish {
itemCell.itemCellView.backgroundColor = UIColor(red: 0, green: 123, blue: 0)
} else {
itemCell.itemCellView.backgroundColor = UIColor.white
}
If I understood your question right, You should hold the isFinish flag somewhere out of the cell, because it's being reused by tableView.
You can create the finished = [Bool]() is your UIViewController and every time check finished[indexPath.row] to see if it's marked or not and pass the boolean to your cell.
After looking into a myriad of StackOverflow posts, nothing really answers how to delete a UITableViewCell with swipe-to-dismiss while fading and without the red delete button.
My Tableviewcell looks like a card, so the red frame of the delete button breaks the sense of continuity and elevation of these cells with card shapes.
Here is the code I am currently using to delete, which does not fade despite the .fade on the UITableViewRowAnimation.
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .none
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
self.pastOrders.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
Here's a screenshot of the behavior I am trying to achieve:
Output 3
//TO CHANGE "DELETE" TITLE COLOR
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let toDelete = UITableViewRowAction(style: .normal, title: "") { (action, indexPath) in
print("\n\n Delete item at indexPathDelete item at indexPath")
}
let deleteTextImg = swipeCellButtons(labelText: "Delete", textColor: UIColor.darkGray, alphaVal: 1.0)
toDelete.backgroundColor = UIColor(patternImage: deleteTextImg)
return [toDelete]
}
func swipeCellButtons(labelText : String, textColor: UIColor, alphaVal: CGFloat) -> UIImage
{
let commonWid : CGFloat = 40
let commonHei : CGFloat = 70 // ROW HEIGHT
let label = UILabel(frame: CGRect(x: 0, y: 0, width: commonWid, height: commonHei))
label.text = labelText
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 11)
label.textColor = textColor.withAlphaComponent(alphaVal)
UIGraphicsBeginImageContextWithOptions(CGSize(width: self.view.frame.width, height: commonHei), false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(UIColor.clear.cgColor) // YOU CAN GIVE YOUR BGCOLOR FOR DELETE BUTTON
context!.fill(CGRect(x: 0, y: 0, width: (self.view.frame.width) / 3, height: commonHei))
label.layer.render(in: context!)
//If you want to add image instead of text, uncomment below lines.
//Then, comment this "label.layer.render(in: context!)" line
//var img: UIImage = UIImage(named: "deleteIcon")!
//img.draw(in: CGRect(x: 0, y: 0, width: 30, height: 30))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
Output 2:
// INSIDE CELL FOR ROW AT INDEXPATH
// COMMENT THIS LINE
//cell.addGestureRecognizer(swipeGesture)
// CELL FADE WILL NOT WORK HERE
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let toDelete = UITableViewRowAction(style: .normal, title: " ") { (action, indexPath) in
print("\n\n Delete item at indexPathDelete item at indexPath")
}
toDelete.backgroundColor = .white
return [toDelete]
}
Output 1:
// GLOBAL DECLARATION
var gotCell : DefaultTableViewCell?
var alphaValue : CGFloat = 1.0
var deletingRowIndPath = IndexPath()
// INSIDE CELL FOR ROW AT INDEXPATH
//let cell = tableView.dequeueReusableCell(withIdentifier: "default", for: indexPath) as! DefaultTableViewCell
let cell = DefaultTableViewCell() // Add this line and comment above line. The issue is `dequeuingreusingcell`. In this method, it will stop dequeuing. But, we have to customise `UITableViewCell` in coding.
let swipeGesture = UIPanGestureRecognizer(target: self, action: #selector(handleSwipe))
swipeGesture.delegate = self
cell.addGestureRecognizer(swipeGesture)
func handleSwipe(panGesture: UIPanGestureRecognizer) {
if panGesture.state == UIGestureRecognizerState.began {
let cellPosition = panGesture.view?.convert(CGPoint.zero, to: defTblVw)
let indPath = defTblVw.indexPathForRow(at: cellPosition!)
deletingRowIndPath = indPath!
gotCell = defTblVw.cellForRow(at: indPath!) as! DefaultTableViewCell
}
if panGesture.state == UIGestureRecognizerState.changed
{
let isLeftMoving = panGesture.isLeft(theViewYouArePassing: (gotCell)!)
if isLeftMoving == true
{
self.gotCell?.alpha = self.alphaValue
self.gotCell?.frame.origin.x = (self.gotCell?.frame.origin.x)! - 2.5
self.view.layoutIfNeeded()
self.alphaValue = self.alphaValue - 0.005
}
else // ADD THIS ELSE CASE
{
self.alphaValue = 1.0
self.gotCell?.alpha = 1.0
UIView.animate(withDuration: 0.8, animations: {
self.gotCell?.frame.origin.x = 0
self.view.layoutIfNeeded()
}) { (value) in
}
}
}
if panGesture.state == UIGestureRecognizerState.ended
{
self.alphaValue = 1.0
if (self.gotCell?.frame.origin.x)! < CGFloat(-(defTblVw.frame.size.width - 90))
{
myArr.remove(at: (deletingRowIndPath.row))
defTblVw.beginUpdates()
defTblVw.deleteRows(at: [deletingRowIndPath], with: UITableViewRowAnimation.fade)
defTblVw.endUpdates()
}
else
{
UIView.animate(withDuration: 0.8, animations: {
self.gotCell?.alpha = 1.0
self.gotCell?.frame.origin.x = 0
self.view.layoutIfNeeded()
}) { (value) in
}
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
extension UIPanGestureRecognizer {
func isLeft(theViewYouArePassing: UIView) -> Bool {
let velocityVal : CGPoint = velocity(in: theViewYouArePassing)
if velocityVal.x >= 0 {
return false
}
else
{
print("Gesture went other")
return true
}
}
}
=============================
I guess SwipeCellKit pod is an option as well to do swiping without delete button, so please check out this link: https://github.com/SwipeCellKit/SwipeCellKit.
There is all documentation how you can customize it and if you can see the Destructive gif on the link, it is what you wanted, however you have to make it custom so there is no other buttons nor the delete button as well.
I hope it helped you somehow.
You can use this library with .exit mode
and In your cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SwipyCell //User You cell identifier and class of cell here
let checkView = viewWithImageName("check") //Use some white dummy image
cell.addSwipeTrigger(forState: .state(0, .left), withMode: .exit, swipeView: checkView, swipeColor: tableView.backgroundView?.backgroundColor, completion: { cell, trigger, state, mode in
print("Did swipe \"Checkmark\" cell")
})
return cell
}
Hope this will help you
Try this code.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let toDelete = UITableViewRowAction(style: .normal, title: " ") { (action, indexPath) in
self.rows.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
toDelete.backgroundColor = .white
return [toDelete]
}
Hope it would help you.
You can animate the content view and on completion of animation you can delete the cell
You can add a swipe gesture on the content of your custom cell, when the swipe animation is over you call a delegate method to the ViewController in which it will update the data array delete the tableView row and reload the tableView.
I was trying to go about making the actions for a UITableViewCell overlap the content of the cell, like in the National Geographic app:
table view
table view when swiped
I tried using a listener on the contentView of the cell to track the frame and keep it constant, but I was unable to get that to work (although it's possible it would, I'm kinda new to iOS).
If anyone has any suggestions for creating a similar effect, they would be much appreciated!
u can make your own custom cell and add a delete button and swipe gestures to make like button overlap the contents of the cell for example, try it out yourself, first create a sample project with single view app, and proceed
subclass the tabview cell with xib option selected and name it something like CustomCell , and in CustomCell.swift class past below code
import UIKit
class CustomCell: UITableViewCell {
var deleteButton:UIButton!
//create a custom cell if not in the reuse pool
class func customCell() -> CustomCell?
{
let aVar:Array = NSBundle.mainBundle().loadNibNamed("CustomCell", owner: nil, options: nil)
if aVar.last!.isKindOfClass(UITableViewCell)
{
return aVar.last as? CustomCell
}
return nil
}
//handle your left swipe
func swipeLeft()
{
print("swipe Left")
self.contentView.bringSubviewToFront(deleteButton!)
var frameRect:CGRect! = deleteButton!.frame
frameRect.origin.x = self.contentView.bounds.size.width - self.deleteButton!.frame.size.width
UIView.animateWithDuration(0.5) { () -> Void in
self.deleteButton!.frame = frameRect
}
}
//aslo the right swipe
func swipeRight()
{
print("swipe right")
var rect:CGRect! = deleteButton?.frame
rect.origin.x = self.contentView.bounds.size.width
UIView.animateWithDuration(0.5) { () -> Void in
self.deleteButton!.frame = rect
}
}
//hear we are adding the delete button in code, if u want add it in xib or (if u are using storyboard )
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
deleteButton = UIButton.init(type: .Custom)
deleteButton.setTitle("Delete", forState: .Normal)
deleteButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
deleteButton.backgroundColor = UIColor.redColor()
self.contentView.addSubview(deleteButton)
let gestureLeft:UISwipeGestureRecognizer = UISwipeGestureRecognizer.init(target: self, action: "swipeLeft")
gestureLeft.direction = .Left
self .addGestureRecognizer(gestureLeft)
let gestureRight:UISwipeGestureRecognizer = UISwipeGestureRecognizer.init(target: self, action: "swipeRight")
gestureRight.direction = .Right
self .addGestureRecognizer(gestureRight)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//set the initial frame of delete button
override func layoutSubviews() {
super.layoutSubviews()
var rect:CGRect! = deleteButton?.frame
rect.size = CGSizeMake(100, 100)
rect.origin.x = self.contentView.bounds.size.width
deleteButton?.frame = rect
}
}
and make sure the tableview cell height to be of 100pt and in view controller set up a tableview in storyboard with datasource and delegate and implement the required delegate and datasource methods
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? CustomCell
if cell == nil
{
cell = CustomCell .customCell()
}
return cell as CustomCell!
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100
}