Всем доброго времени суток!
Для кого эта статья?
Люди у которых коллекция передает только несколько первых данных, а потом циклично их использует.
При создании своего приложения, столкнулся с трудностью передачи информации, c использованием Reusable ячеек коллекции.
Приложение содержит коллекцию ячеек, внутри которых отображаются таблицы с информацией.
Т.к. у нас на одном экране 2 объекта с Reusable ячейками, появляется трудность передачи информации.
Начало будет кратким:
- Создаем проект
- Для удобства выбираем View as: Iphone 8+ (я выбрал потому что он на руках и подобрал под него размеры ячейки)
- На главном контроллере создаем коллекцию
- В size inspector коллекции : Cell size(334:543), Min Spacing(10:80), Sections insets (40:40:40:40)
- Появится вот такая ячейка
- Добавляем таблицу из библиотеки и растягиваем ее
6.1. перетаскиваем (создаем) ячейку таблицы, задаем indentifier “Cell”, style - Basic.
С Сторибордом закончили, переходим к коду
-
ViewController в конечном итоге он будет выглядеть так:
import UIKit class ViewController: UIViewController { //Массив для передачи данных в таблицу let arr = [["table1","table1","table1","table1","table1","table1"], ["table2","table2","table2","table2","table2","table2"], ["table3","table3","table3","table3","table3","table3"], ["table4","table4","table4","table4","table4","table4"], ["table5","table5","table5","table5","table5","table5"], ["table6","table6","table6","table6","table6","table6"]] @IBOutlet weak var collectionView: UICollectionView! override func viewDidLoad() { super.viewDidLoad() //Подписываемся под делегат и датаСорс collectionView.delegate = self //если будете кастомить сами collectionView.dataSource = self //убираем индикаторы положения в коллекции от скрола collectionView.showsVerticalScrollIndicator = false collectionView.showsHorizontalScrollIndicator = false //Включаем страничную прокрутку collectionView.isPagingEnabled = true //Специальная переменная ниже опишу для чего она нужна collectionView.isPrefetchingEnabled = false } } //подписываемся под делегат коллекции extension ViewController: UICollectionViewDelegate { //кастомим если нужно } //и под датаСорс extension ViewController: UICollectionViewDataSource{ func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return arr.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell //массив с данными, которые нам нужно передать, присваиваем в специально созданный массив из класса ячейки cell.dataArr = self.arr[indexPath.row] //обновляем таблицу (на всякий случай) cell.TableView.reloadData() return cell } }
-
Создаем Cocoa touch class и подписываем его под UICollectionViewCell. Сам код с коментами:
Тут могут быть проблемы с присваиванием таблицы к классу ячейки. Выбираем в ассистент эдиторе не авто определение, а работам ручками. Так же при работе в коде, возникает проблема, что Свифт не дает подписать делегат и датасорс таблицы к ячейке. для этого сначала пишем TableView.delegate = self, TableView.dataSource = self через as!, и только потом подписываем расширения.
import UIKit class CollectionViewCell: UICollectionViewCell { @IBOutlet weak var TableView: UITableView! //в этот массив будут передаваться по одному массиву каждый раз когда мы перелистываем ячейку var dataArr = [String]() override func awakeFromNib() { super.awakeFromNib() // подписываем делегат и датаСорс TableView.delegate = self TableView.dataSource = self DispatchQueue.main.async { //наводим красоту по желанию self.TableView.layer.cornerRadius = 13.0 self.TableView.layer.borderWidth = 5 self.TableView.layer.shadowColor = UIColor.darkGray.cgColor self.TableView.layer.shadowOpacity = 0.5 self.TableView.layer.shadowOpacity = 10.0 self.TableView.layer.shadowOffset = .zero self.TableView.layer.shadowPath = UIBezierPath(rect: self.TableView.bounds).cgPath self.TableView.layer.shouldRasterize = true } } } //делегат таблицы extension CollectionViewCell: UITableViewDelegate { //задаем высоту ячейки таблицы func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return tableView.frame.height / CGFloat(dataArr.count) } } //Датасорс таблицы extension CollectionViewCell: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dataArr.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) //присваиваем полученый массив к каждому лейблу ячейки таблицы cell.textLabel?.text = "I'm \(dataArr[indexPath.row])" return cell } }
-
Запускаем.
написано без применения каких либо паттернов. простой пример, не терзайте в коментах об говноКоде… сами переделывайте если не нравится.
Объясняю зачем я создал этот топик.
При создании, вроде бы, такого легкого экрана, возникли проблемы:
-
Как создать страничную коллекцию типа iCarousel - ответ collectionView.isPagingEnabled = true (если нужно чтобы ячейки изменялись при этом в размере - гуглите кастомизацию flowLayot коллекции и добавляйте в проект, много на эту тему есть статей на en-нете
-
Из-за того, что я ячейки пересоздаваемые, на самом деле на экране их 3(видимая, слева, справа, дабы заранее подгрузить данные без грузов), а не одна, и при перелистывании больше 3х ячеек не передавали данные… Если свайпать ячейку вправо серединная ячейка не исчезает, как таковая, она же и выходит слева. по этому коллекция передавала сразу 3 массива по indexPath.row. Решение этой проблемы пришло откуда не ждал.
Свойство collectionView.isPrefetchingEnabled = false - изменяет метод поведения коллекции, а точнее подгрузки ячеек. после выставления false коллекция начинает загружать ячейку только при начале свайпа. Этим самым изменяет и передачу данных из коллекции в ячейку. Теперь данные передаются один за другим.
Но нужно помнить что асинхронность так же важна и для улучшения работоспособности Вашего приложения Apple советует (или требует, я так и не понял) использовать
- var prefetchDataSource: UICollectionViewDataSourcePrefetching?
- collectionView(_:willDisplay:forItemAt:)
Всем спасибо. Особенно спасибо Qonflictorz и swiftBook каналу в тг. Моя первая статья, сильно не ругайте))