iosswifttableviewuigesturerecognizer

TableView Gesture Recognizer Affecting Swipe Delete Row


I have a gesture recognizer in my viewcontroller that pushes the viewcontroller up and down when you swipe up and down. This gesture recognizer is conflicting with my ability to swipe my tableview cell's left to reveal the delete button.

Here is my current code:

import UIKit

class CategoriesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

let categories = "categories"

var settings: UITableView = UITableView()
var parentVC : MapBoxViewController!

var fullView: CGFloat {
    return 65
}
var partialView: CGFloat {
    return UIScreen.main.bounds.height - 65
}

var halfView: CGFloat {
    return (UIScreen.main.bounds.height/2) - 5
}

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.white
    let gesture = UIPanGestureRecognizer.init(target: self, action: #selector(CategoriesViewController.panGesture))
    gesture.delegate = self
    view.addGestureRecognizer(gesture)
    roundViews()
    view.addSubview(settings)

    self.automaticallyAdjustsScrollViewInsets = false
    settings.frame = CGRect(x: 0, y: 65, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height-65)
    settings.delegate = self
    settings.dataSource = self
    settings.separatorColor = UIColor.clear
    settings.register(CategoriesCell.self, forCellReuseIdentifier: "categories")

}

func roundViews() {
    view.layer.cornerRadius = 18
    view.clipsToBounds = true
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func panGesture(recognizer: UIPanGestureRecognizer) {
    let translation = recognizer.translation(in: self.view)
    let velocity = recognizer.velocity(in: self.view)
    let y = self.view.frame.minY
    if ( y + translation.y >= fullView) && (y + translation.y <= partialView ) {
        self.view.frame = CGRect(x: 0, y: y + translation.y, width: view.frame.width, height: view.frame.height)
        recognizer.setTranslation(CGPoint.zero, in: self.view)
    }

    if recognizer.state == .ended {
        var duration =  velocity.y < 0 ? Double((y - fullView) / -velocity.y) : Double((partialView - y) / velocity.y )

        duration = duration > 1.3 ? 1 : duration

        UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.4, options: [.allowUserInteraction], animations: {
            if  velocity.y >= 0 {
                if y > self.halfView {
                    self.view.frame = CGRect(x: 0, y: self.partialView, width: self.view.frame.width, height: self.view.frame.height)
                } else {
                    self.view.frame = CGRect(x: 0, y: self.halfView, width: self.view.frame.width, height: self.view.frame.height)
                }
            } else {
                if y > self.halfView {
                    self.view.frame = CGRect(x: 0, y: self.halfView, width: self.view.frame.width, height: self.view.frame.height)
                } else {
                    self.view.frame = CGRect(x: 0, y: self.fullView, width: self.view.frame.width, height: self.view.frame.height)
                }
            }
        }, completion: nil)
    }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    UIView.animate(withDuration: 0.6, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.2, options: [.allowUserInteraction], animations: {
        let frame = self.view.frame
        self.view.frame = CGRect(x: 0, y: self.halfView, width: frame.width, height: frame.height)
    }, completion: nil)
}

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 5
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 55
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.row == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: categories) as! CategoriesCell
        return cell
    } else if indexPath.row == 1 {
        let cell = tableView.dequeueReusableCell(withIdentifier: categories) as! CategoriesCell
        cell.tripCategoryView.backgroundColor = UIColor(r: 91, g: 192, b: 235)
        cell.tripCategory.text = "Activities"
        return cell
    } else if indexPath.row == 2 {
        let cell = tableView.dequeueReusableCell(withIdentifier: categories) as! CategoriesCell
        cell.tripCategoryView.backgroundColor = UIColor(r: 21, g: 176, b: 151)
        cell.tripCategory.text = "Cultural"
        return cell
    } else if indexPath.row == 3 {
        let cell = tableView.dequeueReusableCell(withIdentifier: categories) as! CategoriesCell
        cell.tripCategoryView.backgroundColor = UIColor(r: 66, g: 230, b: 255)
        cell.tripCategory.text = "Night Life"
        return cell
    } else if indexPath.row == 4 {
        let cell = tableView.dequeueReusableCell(withIdentifier: categories) as! CategoriesCellvv
        cell.tripCategoryView.backgroundColor =  UIColor(r: 183, g: 157, b: 237)
        cell.tripCategory.text = "Bars"
        return cell
    } else {
        let cell = tableView.dequeueReusableCell(withIdentifier: categories) as! AllTripCategoriesCell
        return cell
    }
}
}

extension TripCategoriesViewController: UIGestureRecognizerDelegate {

// Solution
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    let gesture = (gestureRecognizer as! UIPanGestureRecognizer)
    let direction = gesture.velocity(in: view).y

    let y = view.frame.minY
    if (y == fullView && settings.contentOffset.y == 0 && direction > 0) || (y == partialView) {
        settings.isScrollEnabled = false
    } else {
        settings.isScrollEnabled = true
    }

    return false
}
}

Would appreciate if you could help with this. I think I may have to add a gesture recognizer to my custom cell class


Solution

  • You can detect gesture direction before making any actions. It can be possible by using UIGestureRecognizerDelegate gestureRecognizerShouldBegin method:

    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    
        //detecting a direction
        if let recognizer = gestureRecognizer as? UIPanGestureRecognizer {
            let velocity = recognizer.velocity(in: self)
    
            if fabs(velocity.y) > fabs(velocity.x) {
                // this is swipe up/down so you can handle that gesture
                return true
            } else {
                //this is swipe left/right
                //do nothing for that gesture
                return false
            }
        }
        return true
    }
    

    Or you can change it whatever you want. Hope it will help.