Nós criamos o UITableView. Para iniciantes

As férias de Ano Novo já passaram, mas meu desejo de escrever artigos úteis e não muito - não! Hoje falaremos sobre o UITableView , trabalhar com UITableViewDataSource e reutilizar células. Abordaremos como instalar o controlador raiz sem um storyboard, erros ao trabalhar com a tabela, o layout e um cabeçalho grande para a UINavigationBar .


Para quem gosta de piadas engraçadas, gravei um vídeo no YouTube . Bem, aqui tudo será sério. Vamos começar.


Crie um projeto vazio, nomeie o que quiser e vá para o controlador. UIKit tem uma classe UITableViewController . Você pode pesquisar no google muitos tutoriais em que a tabela é mostrada exatamente no contexto desta classe. Mas, para uma melhor compreensão, faremos tudo no UIViewController base.


Na maioria das vezes, quando uma tabela é necessária, o UINavigationController é usado:




Vamos adicionar. No arquivo AppDelegate , a função didFinishLaunchingWithOptions , insira o seguinte código:


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

Um breve programa educacional sobre o motivo: montras e constantes são boas , mas neste tutorial tentaremos ficar sem elas. Esse código ignorará o storyboard (você pode removê-lo) e agrupará o ViewController no UINavigationController .


Seria bom definir um título para o UINavigationBar . Para fazer isso, iremos para a classe ViewController (faremos todo o trabalho adicional aqui) e adicionaremos o seguinte código ao método viewDidLoad :


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

Agora o título será grande e moderno. Executando o projeto, veremos o seguinte:




Fazendo um TableView


Ações preparatórias estão concluídas, podemos passar para a coisa principal. No controlador, crie uma propriedade UITableView . Escolha um inicializador que tenha um parâmetro Style. Defina qualquer quadro, retornaremos a ele mais tarde. E para o estilo, defina Agrupado .


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

Não tenho idéia do porquê desse nome de estilo, mas ele nos permitirá criar uma tabela nativa, como no aplicativo Configurações . Se você precisar de uma tabela não estilizada, use o inicializador apenas com o parâmetro frame.



Layout


Aqui teríamos sido salvos pela constante, mas não procuraremos maneiras fáceis. Vou mostrar o método que eu uso. Obviamente, ele não finge ser canônico, e não é necessário fazê-lo. Declaramos uma função que exporá o quadro às visualizações e o parâmetro assumirá o tamanho do controlador:


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

Você precisa chamar a função em dois lugares - no método viewDidLoad e em 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) } 

Agora a tabela para qualquer orientação será colocada em tela cheia. Você pode adicionar outro processamento ao método updateLayout .


Criando um UITableViewCell


Como o tutorial não trata de células, mas de uma tabela, não vamos nos concentrar na personalização em detalhes. Vamos criar uma classe de célula herdada da base:


 class TableViewCell: UITableViewCell { } 

Para usar a célula na tabela, você precisa registrar a classe. Para fazer isso, no ViewController , chame o seguinte método na tabela:


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

Se a classe for clara, o identificador merece atenção. Em 99% dos casos, a regra funcionará:


  • " Células da mesma classe devem ter o mesmo identificador "

Existem muito poucas situações em que as células da mesma classe precisam de identificadores diferentes e estão associadas principalmente à renderização e animações de código .


Fonte de dados


Esta é uma propriedade que aponta para o objeto que preencherá a tabela. I.e. implementar o protocolo UITableViewDataSource . São necessários dois métodos:


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

O primeiro é responsável pelo número de células na seção. Ainda temos uma seção, uma multi-seção (existe essa palavra?) Não consideraremos. O segundo método é obter o objeto da célula. Funciona astuciosamente, não pense que você mordeu um lutador!


Mas primeiro, vamos adicionar uma matriz de linhas que preencherão a tabela.



Agora vamos seguir para a implementação do primeiro método:


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

Dizemos à tabela que, na seção 0, haverá tantas células quanto elementos na matriz de dados . O segundo método é um pouco mais complicado. É impossível simplesmente inicializar a célula, e tudo por causa do sistema de reutilização de células. Mas não há necessidade de repreender a Apple, na verdade é bom! Para obter o objeto, você precisa chamar o seguinte 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 } 

O método dequeueReusableCell receberá o objeto da célula pelo identificador e nós realizaremos a conversão usando a classe TableViewCell , que deve ser a célula. textLabel é uma propriedade de classe base; nenhuma configuração adicional é necessária.


Resta especificar o dataSource para a tabela e o método viewDidLoad agora deve ter a seguinte aparência:


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

Se executarmos o projeto, veremos uma tabela cheia de conteúdo:




Reutilizar


Até agora, tudo parece estar em ordem. Vamos adicionar um disclosureIndicator para uma das células. Este é um acessório que você definitivamente viu no iOS:



Digamos que a tarefa é definir o indicador apenas para a primeira célula. A primeira coisa que vem à mente é adicionar um método if simples ao cellForRowAt :


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

Mas o inimigo está se escondendo! Vamos executar o projeto e rolar a tabela para fora da tela:



O indicador apareceu pela primeira vez, mas aparece aleatoriamente para outras células! Isso é reutilização - é utilizada uma célula mais conveniente na memória (uma ótima explicação para iniciantes, certo?) E configurada de acordo com o método. Às vezes acontece que uma célula com um indicador é puxada. Como resultado, temos um bug desse tipo. O que fazer


Tudo é simples. Existem duas soluções possíveis. O primeiro está no bloco else e implica essencialmente a configuração inequívoca de qualquer célula. O método ficará assim:


 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 } 

Há outra maneira - implementar o método prepareForReuse na célula. Como o nome indica, o método é chamado antes da reutilização. Tudo que você precisa fazer é redefinir a célula para o padrão. O código fica assim:


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

Existem muitas nuances associadas à reutilização. Por exemplo, a tarefa de carregar imagens para uma célula em segundo plano com paginação, altura adaptável, exclusão e inserção animadas. Mas mais sobre isso na segunda parte, se minhas mãos alcançarem)


Para quem procura


Eu tento gravar regularmente um tutorial no meu canal . Você pode encontrar vídeos sobre como desenhar código ou como criar um controlador do Apple Music player , além de um vídeo neste artigo:


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


All Articles