Evitar la interacción en la subvista de UITableViewCell

Tengo un UITableViewCell grande que tiene 2 UIViews personalizadas en él. Uno de ellos debería permitir la interacción (selección y deselección), y una de las vistas no debería permitir la interacción.

Sé que puedo habilitar o deshabilitar la interacción en toda la celda o en cada una de las subvistas, pero si inhabilita la interacción en la UIView, la celda aún se selecciona o se deselecciona.

¿Hay alguna forma de, por ejemplo, permitir toques en la mitad superior de la celda y no en la inferior?

Aquí hay una captura de pantalla de UITableViewCell que describí

introduzca la descripción de la imagen aquí

Estoy totalmente de acuerdo con JAL , necesitas revisar toda tu estructura celular, pero también sé que a veces y en algunos casos es imposible hacer refactorización.

Entonces, creo que esto, supongamos que tiene un CustomTableViewCell compuesto por dos vistas, nombradas por ejemplo view1 y view2:

El código:

 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) } } 

Al otro lado, donde tiene, por ejemplo, un UIViewController con una 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 } } } 

Algunas cosas importantes :

No olvide establecer la class personalizada correcta para las dos vistas como se explica en esta image:

introduzca la descripción de la imagen aquí

Diría que hay una falla en su implementación, o que tiene un problema X / Y. Considere dividir la celda individual en dos celdas separadas y deshabilitar la selección en la celda inferior.

Si debe avanzar con esta implementación, considere deshabilitar la selección en toda la celda. Coloque un reconocedor de gestos en la subvista superior y toque en forma manual didSelectRowAtIndexPath:

puede reenviar o cancelar toques con testing de éxito

 override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { if let hitView = super.hitTest(point, withEvent: event) { if hitView.isKindOfClass(CustomSubviewClass) { return nil } else { return hitView } } else { return nil } } 

Una forma de hacer que esto funcione es eludir los methods UITableViewDelegate y usar una IBAction con un manejador personalizado de callback en la célula.

  1. Establezca el tipo de selección para la celda en Ninguno para evitar que la celda se select / deselect cuando toque en ella.
  2. Asegúrese de que su UITableViewDelegate no implemente tableView:didSelectRowAtIndexPath .
  3. Agregue una vista de button a la celda y colóquela para que cubra el área con la que desea interactuar.
  4. Agregue @IBAction func buttonTapped(sender: UIButton) en la UITableViewCell .
  5. Agregue una variable de cierre a la celda. Llama al cierre cuando se toca el button.
  6. En el tableView:cellForRowAtIndexPath: delegate establece el cierre en la celda para manejar la llamada.

Ejemplo subclass UITableViewCell :

 class MyTableViewCell: UITableViewCell { var selectionHandler: ((Void) -> Void)? override func prepareForReuse() { // Remove the closure when the cell is recycled. selectionHandler = nil } @IBAction func buttonTapped(sender: UIButton) { // Call the closure when the button is tapped. selectionHandler?() } } 

En tu UITableViewController :

 class MyTableViewController: UITableViewController { override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = .... // Set the closure to be called when the button is tapped. // Using weak self here to prevent a retain cycle. cell.selectionHandler = { [weak self] in self?.selectedCellAtIndexPath(indexPath) } return cell } // We are not using didSelectRowAtIndexPath // override func tableView(tableView: UITableView, didSelectRowAtIndexPath: NSIndexPath) { // } } 

No he probado este código por lo que puede no comstackr, aunque debería servir para ilustrar el concepto.

Desde el editor de properties de vista de tabla, establezca el valor de Selection en No Selection o hágalo mediante progtwigción. Inhabilite la interacción en cada una de las subvistas, excepto la subvista en la que desea realizar la acción. Pase el valor de la fila indexPath a esa subvista como label, tal vez. O subclass esa subvista de UIView para almacenar la información de indexPath. A continuación, implemente el gesto de toque en esa subvista y realice su acción de deseo en el método de reconocimiento de gesto de toque. Espero que estos hagan lo que quieras.