Hacemos UITableView. Para principiantes

Han pasado las vacaciones de Año Nuevo, pero mi deseo de escribir artículos útiles y no muy útiles , ¡no! Hoy hablaremos sobre UITableView , trabajar con UITableViewDataSource y reutilizar celdas. Cubriremos cómo instalar el controlador raíz sin un guión gráfico, errores al trabajar con la tabla, el diseño y un encabezado grande para UINavigationBar .


Para quienes gustan de los chistes, grabé un video en YouTube . Bueno, aquí todo será serio. Empecemos


Cree un proyecto vacío, asígnele el nombre que desee y vaya al controlador. UIKit tiene una clase UITableViewController . Puede buscar en google muchos tutoriales donde la tabla se muestra exactamente en el contexto de esta clase. Pero para una mejor comprensión, haremos todo en la base UIViewController .


La mayoría de las veces, cuando se necesita una tabla, se usa el UINavigationController :




Vamos a agregarlo. En el archivo AppDelegate , la función didFinishLaunchingWithOptions , inserte el siguiente código:


let navigationController = UINavigationController.init(rootViewController: ViewController()) self.window = UIWindow.init(frame: UIScreen.main.bounds) self.window?.rootViewController = navigationController self.window?.makeKeyAndVisible() 

Un breve programa educativo sobre por qué: los tableros de almacenamiento y las constantes son buenos , pero en este tutorial intentaremos prescindir de ellos. Este código ignorará el guión gráfico (puede eliminarlo) y envolverá el ViewController en el UINavigationController .


Sería bueno establecer un título para la UINavigationBar . Para hacer esto, iremos a la clase ViewController (haremos todo el trabajo aquí) y agregaremos el siguiente código al método viewDidLoad :


 self.view.backgroundColor = UIColor.white self.navigationItem.title = "Table" self.navigationController?.navigationBar.prefersLargeTitles = true 

Ahora el título será grande y moderno. Al ejecutar el proyecto, veremos lo siguiente:




Hacer una vista de tabla


Las acciones preparatorias se completan, podemos pasar a lo principal. En el controlador, cree una propiedad UITableView . Elija un inicializador que tenga un parámetro Style. Establezca cualquier marco, volveremos a él más tarde. Y por estilo, establece Agrupado .


 let tableView = UITableView.init(frame: .zero, style: UITableView.Style.grouped) 

No tengo idea de por qué este nombre de estilo es, pero nos permitirá crear una tabla nativa, como en la aplicación Configuración . Si necesita una tabla no estilizada, use el inicializador solo con el parámetro de marco.



Diseño


Aquí habríamos sido salvados por la constante, pero no buscaremos formas fáciles. Mostraré el método que uso. Por supuesto, él no pretende ser canónico, y no es necesario hacerlo. Declaramos una función que expondrá el marco a las vistas, y el parámetro tomará el tamaño del controlador:


 private func updateLayout(with size: CGSize) { self.tableView.frame = CGRect.init(origin: .zero, size: size) } 

Debe llamar a la función en dos lugares: en el método viewDidLoad y en viewWillTransition :


 override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: { (contex) in self.updateLayout(with: size) }, completion: nil) } 

Ahora la tabla para cualquier orientación se colocará en pantalla completa. Puede agregar otro procesamiento al método updateLayout .


Hacer una UITableViewCell


Dado que el tutorial no trata sobre celdas, sino sobre una tabla, no nos detendremos en la personalización en detalle. Hagamos una clase de celda heredada de la base:


 class TableViewCell: UITableViewCell { } 

Para usar la celda en la tabla, debe registrar la clase. Para hacer esto, en ViewController , llame al siguiente método en la tabla:


 self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell") 

Si la clase es clara, entonces el identificador merece atención. En el 99% de los casos, la regla funcionará:


  • " Las celdas de la misma clase deben tener el mismo identificador "

Hay muy pocas situaciones en las que las celdas de la misma clase necesitan identificadores diferentes, y están asociadas principalmente con la representación de código y las animaciones.


Fuente de datos


Esta es una propiedad que apunta al objeto que llenará la tabla. Es decir implementar el protocolo UITableViewDataSource . Se requieren dos métodos:


 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {} func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {} 

El primero es responsable del número de celdas en la sección. Todavía tenemos una sección, una multisección (¿existe esa palabra?) No la consideraremos. El segundo método es obtener el objeto de celda. Funciona astutamente, ¡no pienses que has mordido a un luchador!


Pero primero, agreguemos una matriz de filas que llenarán la tabla.



Ahora pasemos a implementar el primer método:


 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch tableView { case self.tableView: return self.data.count default: return 0 } } 

Le decimos a la tabla que en la sección 0 habrá tantas celdas como elementos en la matriz de datos . El segundo método es un poco más complicado. Es imposible simplemente inicializar la celda, y todo debido al sistema de reutilización de celdas. Pero no hay necesidad de regañar a Apple, ¡en realidad es bueno! Para obtener el objeto, debe llamar al siguiente código:


 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell cell.textLabel?.text = self.data[indexPath.row] return cell } 

El método dequeueReusableCell recibirá el objeto de celda por identificador, y lo convertiremos usando type en cuanto a la clase TableViewCell , que debería ser la celda. textLabel es una propiedad de clase base; no se requiere configuración adicional.


Queda por especificar dataSource para la tabla y el método viewDidLoad ahora debería verse así:


 override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.white self.navigationItem.title = "Table" self.navigationController?.navigationBar.prefersLargeTitles = true self.view.addSubview(self.tableView) self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell") self.tableView.dataSource = self self.updateLayout(with: self.view.frame.size) } 

Si ejecutamos el proyecto, veremos una tabla llena de contenido:




Reutilizar


Hasta ahora, todo parece estar en orden. Agreguemos un indicador de divulgación para una de las celdas. Este es un accesorio que definitivamente has visto en iOS:



Digamos que la tarea es establecer el indicador solo para la primera celda. Lo primero que viene a la mente es agregar un simple if al método cellForRowAt :


 if indexPath.row == 0 { cell.accessoryType = .disclosureIndicator } 

¡Pero el enemigo se está escondiendo! Ejecutemos el proyecto y saquemos la tabla de la pantalla:



¡El indicador apareció para el primero, pero aparece al azar para otras células! Esto es reutilizar: se toma una celda que es más conveniente en la memoria (una gran explicación para principiantes, ¿verdad?) Y se configura de acuerdo con el método. A veces sucede que se tira una celda con un indicador. Como resultado, tenemos ese error. Que hacer


Todo es simple Hay dos posibles soluciones. El primero está en el bloque else e implica esencialmente la configuración inequívoca de cualquier celda. El método se verá así:


 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell cell.textLabel?.text = self.data[indexPath.row] if indexPath.row == 0 { cell.accessoryType = .disclosureIndicator } else { cell.accessoryType = .none } return cell } 

Hay otra forma: implementar el método prepareForReuse en la celda. Como su nombre lo indica, se llama al método antes de reutilizarlo. Todo lo que necesita hacer es restablecer la celda a los valores predeterminados. El código se ve así:


 class TableViewCell: UITableViewCell { override func prepareForReuse() { super.prepareForReuse() self.accessoryType = .none } } 

Hay muchos matices asociados con la reutilización. Por ejemplo, la tarea de cargar imágenes para una celda en segundo plano con paginación, altura adaptativa, eliminación animada e inserción. Pero más sobre eso en la segunda parte, si mis manos alcanzan)


Para los buscadores


Intento grabar regularmente un tutorial en mi canal . Puede encontrar videos sobre cómo dibujar código o cómo hacer un controlador de reproductor de Apple Music , así como un video sobre este artículo:


Source: https://habr.com/ru/post/es436390/


All Articles