Как сверстать таблицу с горизонтальной и вертикальной ячейками?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Верстка таблицы с горизонтальными и вертикальными ячейками в iOS
В iOS разработке под "таблицей с горизонтальными и вертикальными ячейками" обычно понимается UICollectionView с различными типами ячеек, организованными в сетку или сложную компоновку. В отличие от UITableView, которая поддерживает только вертикальную прокрутку с однотипными ячейками, UICollectionView дает полную свободу в создании любых макетов через UICollectionViewLayout и его подклассы.
Основные подходы к реализации
1. UICollectionViewFlowLayout с кастомными размерами
Самый простой способ создать таблицу с разными ячейками - настроить UICollectionViewFlowLayout, задавая разные размеры для ячеек через делегатные методы:
class CustomFlowLayoutViewController: UIViewController {
private var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical // или .horizontal для горизонтальной таблицы
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 1
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(VerticalCell.self, forCellWithReuseIdentifier: "vertical")
collectionView.register(HorizontalCell.self, forCellWithReuseIdentifier: "horizontal")
view.addSubview(collectionView)
}
}
extension CustomFlowLayoutViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.item % 3 == 0 {
// Вертикальная ячейка (высокая и узкая)
return CGSize(width: (collectionView.bounds.width / 2) - 1, height: 200)
} else {
// Горизонтальная ячейка (широкая и низкая)
return CGSize(width: collectionView.bounds.width - 1, height: 100)
}
}
}
2. UICollectionViewCompositionalLayout (рекомендуемый с iOS 13)
Современный и мощный подход, который позволяет создавать сложные таблицы с комбинацией горизонтальных и вертикальных ячеек:
func createCompositionalLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout { sectionIndex, layoutEnvironment in
// Вертикальная группа (столбец)
let verticalItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.5),
heightDimension: .fractionalHeight(1.0)
)
let verticalItem = NSCollectionLayoutItem(layoutSize: verticalItemSize)
// Горизонтальная группа (ряд)
let horizontalItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.5)
)
let horizontalItem = NSCollectionLayoutItem(layoutSize: horizontalItemSize)
// Создаем вложенную группу, комбинирующую оба типа ячеек
let verticalGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.5),
heightDimension: .fractionalHeight(1.0)
),
subitems: [verticalItem, horizontalItem]
)
let horizontalGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.5),
heightDimension: .fractionalHeight(1.0)
),
subitems: [horizontalItem, verticalItem]
)
// Объединяем группы в общую группу секции
let nestedGroupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(300)
)
let nestedGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: nestedGroupSize,
subitems: [verticalGroup, horizontalGroup]
)
let section = NSCollectionLayoutSection(group: nestedGroup)
return section
}
return layout
}
3. Кастомный UICollectionViewLayout
Для максимальной гибкости и контроля можно создать свой собственный layout:
class CustomTableLayout: UICollectionViewLayout {
private var cache: [UICollectionViewLayoutAttributes] = []
private var contentHeight: CGFloat = 0
private var contentWidth: CGFloat {
guard let collectionView = collectionView else { return 0 }
return collectionView.bounds.width
}
override func prepare() {
guard cache.isEmpty, let collectionView = collectionView else { return }
var xOffset: CGFloat = 0
var yOffset: CGFloat = 0
for item in 0..<collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
// Определяем размер ячейки на основе её позиции
let isVerticalCell = indexPath.item % 2 == 0
let cellWidth = isVerticalCell ? contentWidth / 2 : contentWidth
let cellHeight = isVerticalCell ? 200 : 100
// Позиционируем ячейку
attributes.frame = CGRect(x: xOffset, y: yOffset,
width: cellWidth, height: cellHeight)
cache.append(attributes)
// Обновляем смещения для следующей ячейки
if isVerticalCell {
xOffset += cellWidth
if xOffset >= contentWidth {
xOffset = 0
yOffset += cellHeight
}
} else {
xOffset = 0
yOffset += cellHeight
}
contentHeight = max(contentHeight, attributes.frame.maxY)
}
}
}
Практические советы по реализации
- Регистрация разных типов ячеек:
collectionView.register(VerticalTableViewCell.self,
forCellWithReuseIdentifier: "VerticalCell")
collectionView.register(HorizontalTableViewCell.self,
forCellWithReuseIdentifier: "HorizontalCell")
- Настройка ячеек в data source:
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item % 2 == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VerticalCell",
for: indexPath) as! VerticalTableViewCell
cell.configure(with: data[indexPath.item])
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HorizontalCell",
for: indexPath) as! HorizontalTableViewCell
cell.configure(with: data[indexPath.item])
return cell
}
}
- Обработка различных ориентаций устройства:
override func viewWillTransition(to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate { _ in
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
Ключевые моменты для собеседования:
- UICollectionView - основной инструмент для создания сложных таблиц с разными типами ячеек
- UICollectionViewCompositionalLayout - современный API для создания адаптивных макетов
- Делегатные методы sizeForItemAt позволяют динамически задавать размеры ячеек
- Правильная обработка переиспользования ячеек через prepareForReuse()
- Инвалидация лейаута при изменении размеров или контента
- Эффективность через кэширование вычислений в кастомных лейаутах
Для создания действительно сложных таблиц с комбинацией горизонтальных и вертикальных ячеек лучше всего использовать UICollectionViewCompositionalLayout, так как он предоставляет декларативный API, отличную производительность и встроенную поддержку различных размеров классов и ориентаций устройства.