ios uitableview swift uibutton

ios - Detectando el uibutton en tableview: Mejores prácticas de Swift



uitableview (9)

Como seguimiento de los comentarios de @Lyndsey y @ longbow, noté que cuando tenía el segue en el guión gráfico yendo del botón al destinationVC, se llamaba a prepareForSegue antes de que la función buttonClicked pudiera actualizar la variable urlPath. Para resolver esto, configuré el segue directamente desde el primer VC al destinationVC, y tuve el segue realizado programáticamente después de que se ejecutó el código en el botónClicked. Tal vez no es ideal, pero parece estar funcionando.

func buttonClicked(sender:UIButton) { let studentDic = tableData[sender.tag] as NSDictionary let studentIDforTherapyInt = studentDic["ID"] as Int studentIDforTherapy = String(studentIDforTherapyInt) urlPath = "BaseURL..."+studentIDforTherapy self.performSegueWithIdentifier("selectTherapySegue", sender: sender) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { if (segue.identifier == "selectTherapySegue") { let svc = segue.destinationViewController as SelectTherapyViewController; svc.urlPath = urlPath }

Tengo una vista de tabla con un número variable de celdas que representan a los estudiantes que corresponden a su instructor particular. Son células personalizadas con un botón que desencadena una transición a un nuevo CV, generando información detallada sobre el estudiante de cuya celda se trataba. Mi pregunta es:

¿Cuál es la mejor práctica rápida para identificar qué botón se presionó?

Una vez que conozco la ruta del índice, puedo identificar qué información del estudiante necesita pasar al siguiente CV. Hay una gran respuesta para el objetivo C en la publicación a continuación, pero no estoy seguro de cómo traducir a Swift. Cualquier ayuda sería muy apreciada.

Detectando qué UIButton se presionó en una UITableView


Iba a usar el enfoque indexPath hasta que llegué a entender que no sería confiable / incorrecto en algunas situaciones (por ejemplo, eliminar o mover la celda).

Lo que hice es más simple. Por ejemplo, estoy mostrando una serie de colores y sus valores RGB, uno por celda de vista de tabla. Cada color se define en una matriz de estructuras de color. Para mayor claridad, estos son:

struct ColorStruct { var colorname:String = "" var red: Int = 0 var green: Int = 0 var blue: Int = 0 } var colors:[ColorStruct] = [] // The color array

Mi prototipo de celda tiene una var para mantener el índice / clave real en mi matriz:

class allListsCell: UITableViewCell { @IBOutlet var cellColorView: UIView! @IBOutlet var cellColorname: UILabel! var colorIndex = Int() // ---> points directly back to colors[] @IBAction func colorEditButton(_ sender: UIButton, forEvent event: UIEvent) { print("colorEditButton: colors[] index:/(self.colorIndex), /(colors[self.colorIndex].colorname)") } }

Esta solución toma tres líneas de código, una en la definición de celda prototipo , la segunda en la lógica que puebla una nueva celda, y la tercera en la función IBAction que se llama cuando se presiona el botón de cualquier celda. Debido a que efectivamente he ocultado la "clave" (índice) a los datos en cada celda AS estoy poblando esa nueva celda, no se requiere cálculo, y si mueve las celdas no hay necesidad de actualizar nada.


Lo estoy haciendo a través de prepareforSegue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { let indexPath = self.tableView.indexPathForSelectedRow() let item = tableViewCollection[indexPath!.row].id let controller = segue.destinationViewController as? DetailVC controller?.thisItem = item }

y en el siguiente controlador solo voy a volver a cargar las propiedades completas del elemento, conociendo su id y configurándolo en var thisItem en DetailVC


Nunca es una buena idea usar etiquetas para identificar celdas e indexPaths, eventualmente terminarás con un indexPath incorrecto y consecuentemente la celda e información incorrecta.

Te sugiero que pruebes el siguiente código (Trabajar con UICollectionView, no lo probé con un TableView, pero probablemente funcione bien):

SWIFT 4

@objc func buttonClicked(_ sender: UIButton) { if let tableView = tableViewNameObj { let point = tableView.convert(sender.center, from: sender.superview!) if let wantedIndexPath = tableView.indexPathForItem(at: point) { let cell = tableView.cellForItem(at: wantedIndexPath) as! SpecificTableViewCell } } }


Otra posible solución sería usar dispatch_block_t . Si lo haces con Storyboard, primero tienes que crear una variable miembro en tu clase UITableViewCell personalizada.

var tapBlock: dispatch_block_t?

Luego debes crear un IBAction y llamar a tapBlock .

@IBAction func didTouchButton(sender: AnyObject) { if let tapBlock = self.tapBlock { tapBlock() } }

En su controlador de vista con UITableView simplemente puede reaccionar al botón de eventos como este

let cell = tableView.dequeueReusableCellWithIdentifier("YourCellIdentifier", forIndexPath: indexPath) as! YourCustomTableViewCell cell.tapBlock = { println("Button tapped") }

Sin embargo, debe tener en cuenta al acceder a self dentro del bloque, para no crear un ciclo de retención. Asegúrese de acceder a él como [weak self] .


Swift 3

@ cellForRowAt indexPath

cell.Btn.addTarget(self, action: #selector(self.BtnAction(_:)), for: .touchUpInside)

Entonces

func BtnAction(_ sender: Any) { let btn = sender as? UIButton }


Actualizado para Swift 3

Si lo único que desea hacer es activar un segue en un toque, sería contrario a las mejores prácticas hacerlo a través de un UIButton. Simplemente puede usar el controlador integrado de UIKit para seleccionar una celda, es decir, func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) . Puede implementarlo haciendo algo como lo siguiente:

Crear una UITableViewCell personalizada

class StudentCell: UITableViewCell { // Declare properties you need for a student in a custom cell. var student: SuperSpecialStudentObject! // Other code here... }

Cuando cargue su UITableView, pase los datos a la celda desde su modelo de datos:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "StudentCell", for: indexPath) as! StudentCell cell.student = superSpecialDataSource[indexPath.row] return cell }

Luego use didSelectRow atIndexPath para detectar cuándo se ha seleccionado una celda, acceder a la celda y sus datos, y pasar el valor como parámetro para realizar la performSegue .

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) as! StudentCell if let dataToSend = cell.student { performSegue(withIdentifier: "DestinationView", sender: dataToSend) } }

Y finalmente en prepareForSegue :

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "DestinationView" { let destination = segue.destination as! DestinationViewController if let dataToSend = sender as? SuperSpecialStudentObject { destination.student = dataToSend } } }

Alternativamente, si desea que solo seleccionen una parte de la celda en lugar de tocar en cualquier lugar dentro de la celda, puede agregar un elemento accesorio a la celda, como el elemento accesorio detallado (se parece al círculo con una "i" dentro de ) y utilice el override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) lugar.


Solución Swift 3.0

cell.btnRequest.tag = indexPath.row cell.btnRequest.addTarget(self,action:#selector(buttonClicked(sender:)), for: .touchUpInside) func buttonClicked(sender:UIButton) { let buttonRow = sender.tag }


Si su código lo permite, le recomiendo que configure la etiqueta UIButton igual a indexPath.row , de modo que cuando se indexPath.row su acción, puede extraer la etiqueta y, por lo tanto, remar los datos del botón durante el método desencadenado. Por ejemplo, en cellForRowAtIndexPath puede establecer la etiqueta:

button.tag = indexPath.row button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

luego en el buttonClicked: puedes buscar la etiqueta y, por lo tanto, la fila:

func buttonClicked(sender:UIButton) { let buttonRow = sender.tag }

De lo contrario, si eso no es propicio para su código por alguna razón, la traducción de Swift de este Objective-C responde que está vinculado a :

- (void)checkButtonTapped:(id)sender { CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition]; if (indexPath != nil) { ... } }

es:

func checkButtonTapped(sender:AnyObject) { let buttonPosition = sender.convert(CGPoint.zero, to: self.tableView) let indexPath = self.tableView.indexPathForRow(at: buttonPosition) if indexPath != nil { ... } }