Swipe Actions are not working on Section header - ios

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
}

Related

Swiping on a tableview is deselecting all selected rows trailingSwipeActionsConfigurationForRowAt

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

UIContextualAction delete row issue. UIContextualAction's menu overlaps the cell

I have two UIContextualActions which should delete rows from the table after completion. I faced the following intermittent issue:
If I apply this actions very fast one by one, then the first action works fine, but when I call UIContextualAction's menu for the second time it overlaps the cell. In the third time, it is not possible to call UIContextualAction's menu until tableView is scrolled. Here the short video.
Please find below the piece of code
//MARK: Swipe actions
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = self.contextualDeleteAction(forRowAtIndexPath: indexPath)
let markAsReadAction = self.contextualMarkAsReadAction(forRowAtIndexPath: indexPath)
let markAsUnreadAction = self.contextualMarkAsUnreadAction(forRowAtIndexPath: indexPath)
let swipeConfig = UISwipeActionsConfiguration(actions: [
isArchiveModeEnabled ? markAsUnreadAction : markAsReadAction,
deleteAction
])
swipeConfig.performsFirstActionWithFullSwipe = false
return swipeConfig
}
func contextualMarkAsUnreadAction(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction {
let action = UIContextualAction(style: .normal, title: "") { _, _, completion in
let index = indexPath.row
if let article = self.getSelectedArticleByIndex(index) {
self.articlesManager.restore(article: article)
self.refreshDataSource()
self.tableView.deleteRows(at: [indexPath], with: .automatic)
self.tableView.isEditing = false //seems like it helps to fix visual bug when the action is left on blank space
completion(true)
}
}
action.backgroundColor = UIColor(patternImage: swipeActinImages.markAsUnread)
return action
}
refreshDataSource function do the following:
private func refreshDataSource() {
articles = isArchiveModeEnabled ? dataController.getArchivedArticles() : dataController.getUnreadArticles()
}
private func reloadTableData() {
if dataController.getActiveUser() != nil {
refreshDataSource()
introView?.isHidden = articles.count != 0 || isArchiveModeEnabled
tableView.isScrollEnabled = (introView?.isHidden)!
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
Appreciate any help
UPDATE
So I solved it. I've replaced UIContextualAction(style: .normal, title: "") to UIContextualAction(style: .destructive, title: "") and don't update datasource manualy anymore. Completion(true) do all needed manipulation with cell and table
automaticaly.
The final code is
func contextualMarkAsUnreadAction(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction {
let action = UIContextualAction(style: .destructive, title: "") { _, _, completion in
let index = indexPath.row
if let article = self.getSelectedArticleByIndex(index) {
self.articlesManager.restore(article: article)
//self.refreshDataSource()
completion(true)
} else {
completion(false)
}
}
action.backgroundColor = UIColor(patternImage: swipeActinImages.markAsUnread)
return action
}

How to set clear background in table view cell swipe action?

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

How to delete UITableViewCell with swipe-to-dismiss with fade effect and no red delete button?

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.

Reload particular section on button click in swift 4

I am trying to reload a particular section on button click in swift 4.For that,I am using following code:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView:CustomCell = tableView.dequeueReusableCell(withIdentifier: "reuseCell") as! CustomCell
let dict:[String:Any]=array[section]
let firstKey = Array(dict.keys)[0]
headerView.categoryLabel.text=firstKey
headerView.categoryLabel.textColor = UIColor.black
currentSection=section
print("value of section and current section here %#%#",section,currentSection)
let tapRecognizer = UIButton()
tapRecognizer.frame = CGRect.init(x: 0, y:10, width:self.tableView.frame.size.width, height:50)
//tapRecognizer.backgroundColor=UIColor.red
tapRecognizer.tag=section
tapRecognizer.addTarget(self, action: #selector(tapOnHeaderView(_sender:)), for: .touchUpInside)
headerView.addSubview(tapRecognizer)
return headerView;
}
#objc func tapOnHeaderView(_sender:UIButton){
print("value of sender tag","\(_sender.tag)")
onReload = true
print("value of index vala tag",IndexSet(integer: _sender.tag))
let sectionToReload = 0
let indexSet: IndexSet = [sectionToReload]
self.tableView.reloadSections(indexSet, with: .automatic)
}
extension ViewController:UITableViewDelegate{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if(indexPath.section==0){
if(!onReload){
return 0
}else{
return 40
}}
else{
if(!onReload){
return 0
}else{
return 40
}
}
}
When I click on any button ,it is expected that only section 0 gets reload. But, infact when I click on button section 0 and section 1 both gets reloaded.Kindly help me to resolve this problem.
#objc func tapOnHeaderView(_sender:UIButton){
print("value of sender tag","\(_sender.tag)")
onReload = true
print("value of index vala tag",IndexSet(integer: _sender.tag))
self.tableView.reloadSections([0], with: .automatic)
}
Please replace with this code and check whether it works for you

Resources