← Назад к вопросам

Как сверстать таблицу с горизонтальной и вертикальной ячейками?

1.7 Middle🔥 111 комментариев
#UIKit и верстка

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Верстка таблицы с горизонтальными и вертикальными ячейками в 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)
        }
    }
}

Практические советы по реализации

  1. Регистрация разных типов ячеек:
collectionView.register(VerticalTableViewCell.self, 
                       forCellWithReuseIdentifier: "VerticalCell")
collectionView.register(HorizontalTableViewCell.self, 
                       forCellWithReuseIdentifier: "HorizontalCell")
  1. Настройка ячеек в 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
    }
}
  1. Обработка различных ориентаций устройства:
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, отличную производительность и встроенную поддержку различных размеров классов и ориентаций устройства.

Как сверстать таблицу с горизонтальной и вертикальной ячейками? | PrepBro