mattgabor mattgabor - 4 months ago 31
Swift Question

Prevent interaction on subview of UITableViewCell

I have a large UITableViewCell that has 2 custom UIViews in it. One of them should allow interaction (selection and deselection), and one of the views should not allow interaction.

I know I can enable or disable interaction on the entire cell, or on each of the subviews, but if I disable interaction on the UIView the cell still becomes selected or deselected.

Is there a way to, for example, allow touches on the top half of the cell and not the bottom?

Here's a screenshot of the UITableViewCell I described

enter image description here

Answer

I totally agree with JAL, you need to review all your cell structure, but I know also that sometimes and in some cases it's impossible doing refactor.

So , I think this, suppose you have a CustomTableViewCell composed by two views , named for example view1 and view2:

The code:

class MyView1 : UIView {
    var isTouched : Bool = false
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.isTouched = true
        self.nextResponder()?.touchesBegan(touches, withEvent: event)
    }
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.isTouched = false
        self.nextResponder()?.touchesEnded(touches, withEvent: event)
    }
}
class MyView2 : UIView {
    var isTouched : Bool = false
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.isTouched = true
        self.nextResponder()?.touchesBegan(touches, withEvent: event)
    }
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.isTouched = false
        self.nextResponder()?.touchesEnded(touches, withEvent: event)
    }
}
class CustomTableViewCell: UITableViewCell {
    @IBOutlet weak var myExampleLabel: UILabel!
    @IBOutlet weak var view1: MyView1!
    @IBOutlet weak var view2: MyView2!

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        print("situation: myView1 : \(self.view1.isTouched) myView2: \(self.view2.isTouched)")
        var responder : UIResponder! = self
        while responder.nextResponder() != nil {
           responder = responder.nextResponder()
           if responder is SimpleTableView.ViewController { // the name of your tableView delegate class
                let vc = responder as! ViewController
                let indexPath = vc.tableView.indexPathForCell(self)
                vc.tableView(vc.tableView, didSelectRowAtIndexPath: indexPath!)
            }
        }
        super.touchesBegan(touches, withEvent: event)
    }
}

To the other side, where you have for example a UIViewController with a UITableView:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet var tableView: UITableView!
    var items: [String] = ["We", "Heart", "Swift", "So", "Much"]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 140.0
        self.tableView.registerNib(UINib(nibName: "CustomTableViewCell", bundle:nil), forCellReuseIdentifier: "CustomTableViewCell")
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count;
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("CustomTableViewCell", forIndexPath: indexPath) as! CustomTableViewCell
        cell.myExampleLabel.text = self.items[indexPath.row]
        return cell
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomTableViewCell
        print("row = %d",indexPath.row)
        if cell.view1.isTouched { 
           print("tableView: touched view 1") 
           // do whatever you want with cell.view1
           // if you want you can disable cell.view2.userInteractionEnabled
        }
        else {
            print("tableView: touched view 2")
            // same thing for cell.view2
        }
    }
}

Some important things:

Don't forget to set the correct Custom Class for the two views like explained in this picture:

enter image description here

Comments