214 lines
10 KiB
Swift
214 lines
10 KiB
Swift
|
|
//
|
||
|
|
// VideoSeatLayout.swift
|
||
|
|
// TUIVideoSeat
|
||
|
|
//
|
||
|
|
// Created by janejntang on 2023/3/16.
|
||
|
|
//
|
||
|
|
|
||
|
|
import Foundation
|
||
|
|
|
||
|
|
protocol VideoSeatLayoutDelegate: AnyObject {
|
||
|
|
func updateNumberOfPages(numberOfPages: NSInteger)
|
||
|
|
}
|
||
|
|
|
||
|
|
class VideoSeatLayout: UICollectionViewFlowLayout {
|
||
|
|
private var prePageCount: NSInteger = 1
|
||
|
|
|
||
|
|
private var collectionViewHeight: CGFloat {
|
||
|
|
return collectionView?.bounds.height ?? UIScreen.main.bounds.height
|
||
|
|
}
|
||
|
|
|
||
|
|
private var collectionViewWidth: CGFloat {
|
||
|
|
return collectionView?.bounds.width ?? kScreenWidth
|
||
|
|
}
|
||
|
|
|
||
|
|
private var isPortrait: Bool {
|
||
|
|
return collectionViewHeight > collectionViewWidth
|
||
|
|
}
|
||
|
|
|
||
|
|
private var kVideoSeatCellNumberOfOneRow: CGFloat {
|
||
|
|
return isPortrait ? 2 : 3
|
||
|
|
}
|
||
|
|
|
||
|
|
private var kMaxShowCellCount: Int {
|
||
|
|
return 6
|
||
|
|
}
|
||
|
|
|
||
|
|
private let itemDiffSpace: CGFloat = 5.0
|
||
|
|
|
||
|
|
private var itemWidthHeight: CGFloat {
|
||
|
|
let minimumDistance = min(collectionViewHeight, collectionViewWidth)
|
||
|
|
let availableSpace = minimumDistance - (kVideoSeatCellNumberOfOneRow + 1) * itemDiffSpace
|
||
|
|
if isPortrait {
|
||
|
|
return availableSpace / kVideoSeatCellNumberOfOneRow
|
||
|
|
} else {
|
||
|
|
return availableSpace / (CGFloat(kMaxShowCellCount) / kVideoSeatCellNumberOfOneRow)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private let viewModel: TUIVideoSeatViewModel
|
||
|
|
|
||
|
|
fileprivate var layoutAttributeArray: [UICollectionViewLayoutAttributes] = []
|
||
|
|
|
||
|
|
init(viewModel: TUIVideoSeatViewModel) {
|
||
|
|
self.viewModel = viewModel
|
||
|
|
super.init()
|
||
|
|
}
|
||
|
|
|
||
|
|
required init?(coder: NSCoder) {
|
||
|
|
fatalError("init(coder:) has not been implemented")
|
||
|
|
}
|
||
|
|
|
||
|
|
override func prepare() {
|
||
|
|
super.prepare()
|
||
|
|
calculateEachCellFrame()
|
||
|
|
}
|
||
|
|
|
||
|
|
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
|
||
|
|
return layoutAttributeArray
|
||
|
|
}
|
||
|
|
|
||
|
|
override var collectionViewContentSize: CGSize {
|
||
|
|
return CGSize(width: CGFloat(prePageCount) * collectionViewWidth, height: collectionViewHeight)
|
||
|
|
}
|
||
|
|
|
||
|
|
weak var delegate: VideoSeatLayoutDelegate?
|
||
|
|
|
||
|
|
func getMiniscreenFrame(item: VideoSeatItem?) -> CGRect {
|
||
|
|
var height = isPortrait ? 180.0 : 100.0
|
||
|
|
var width = isPortrait ? 100.0 : 180.0
|
||
|
|
if let item = item, !item.hasVideoStream {
|
||
|
|
height = 100.0
|
||
|
|
width = 100.0
|
||
|
|
}
|
||
|
|
return CGRect(x: collectionViewWidth - width - itemDiffSpace, y: itemDiffSpace, width: width, height: height)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - layout
|
||
|
|
|
||
|
|
extension VideoSeatLayout {
|
||
|
|
private func calculateEachCellFrame() {
|
||
|
|
guard let collectionViewWidth: CGFloat = collectionView?.bounds.width else { return }
|
||
|
|
guard viewModel.listSeatItem.count > 0 else { return }
|
||
|
|
layoutAttributeArray = []
|
||
|
|
let section: Int = 0
|
||
|
|
prePageCount = 1
|
||
|
|
if viewModel.videoSeatViewType == .singleType {
|
||
|
|
let indexPath = IndexPath(item: 0, section: 0)
|
||
|
|
let cell = getFullScreenAttributes(indexPath: indexPath)
|
||
|
|
layoutAttributeArray.append(cell)
|
||
|
|
} else if viewModel.videoSeatViewType == .largeSmallWindowType {
|
||
|
|
let largeIndexPath = IndexPath(item: 0, section: section)
|
||
|
|
let largeCell = getFullScreenAttributes(indexPath: largeIndexPath)
|
||
|
|
layoutAttributeArray.append(largeCell)
|
||
|
|
let smallIndexPath = IndexPath(item: 1, section: section)
|
||
|
|
let smallCell = getSmallAttributes(indexPath: smallIndexPath)
|
||
|
|
layoutAttributeArray.append(smallCell)
|
||
|
|
} else if viewModel.videoSeatViewType == .pureAudioType || viewModel.videoSeatViewType == .equallyDividedType {
|
||
|
|
guard let itemCount = collectionView?.numberOfItems(inSection: section) else { return }
|
||
|
|
let isMultipage = itemCount >= kMaxShowCellCount
|
||
|
|
for i in 0 ... itemCount - 1 {
|
||
|
|
let indexPath = IndexPath(item: i, section: section)
|
||
|
|
var cell: UICollectionViewLayoutAttributes
|
||
|
|
if isMultipage {
|
||
|
|
cell = getMultipageEquallyDividedAttributes(indexPath: indexPath, item: i, itemCount: itemCount, leftDiff: 0.0)
|
||
|
|
} else {
|
||
|
|
cell = getEquallyDividedAttributes(indexPath: indexPath, item: i, itemCount: itemCount, leftDiff: 0.0)
|
||
|
|
}
|
||
|
|
layoutAttributeArray.append(cell)
|
||
|
|
}
|
||
|
|
prePageCount = Int(ceil(CGFloat(itemCount) / CGFloat(kMaxShowCellCount)))
|
||
|
|
} else if viewModel.videoSeatViewType == .speechType {
|
||
|
|
guard let itemCount = collectionView?.numberOfItems(inSection: section) else { return }
|
||
|
|
let isMultipage = (itemCount - 1) >= kMaxShowCellCount
|
||
|
|
for i in 0 ... itemCount {
|
||
|
|
let indexPath = IndexPath(item: i, section: section)
|
||
|
|
var cell: UICollectionViewLayoutAttributes
|
||
|
|
if i == 0 {
|
||
|
|
cell = getFullScreenAttributes(indexPath: indexPath)
|
||
|
|
} else if isMultipage {
|
||
|
|
cell = getMultipageEquallyDividedAttributes(indexPath: indexPath, item: i - 1,
|
||
|
|
itemCount: itemCount - 1,
|
||
|
|
leftDiff: collectionViewWidth)
|
||
|
|
} else {
|
||
|
|
cell = getEquallyDividedAttributes(indexPath: indexPath, item: i - 1,
|
||
|
|
itemCount: itemCount - 1,
|
||
|
|
leftDiff: collectionViewWidth)
|
||
|
|
}
|
||
|
|
layoutAttributeArray.append(cell)
|
||
|
|
}
|
||
|
|
prePageCount = Int(ceil(CGFloat(itemCount - 1) / CGFloat(kMaxShowCellCount))) + 1
|
||
|
|
}
|
||
|
|
delegate?.updateNumberOfPages(numberOfPages: prePageCount)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Full screen cell layout information
|
||
|
|
private func getFullScreenAttributes(indexPath: IndexPath) ->
|
||
|
|
UICollectionViewLayoutAttributes {
|
||
|
|
let cell = UICollectionViewLayoutAttributes(forCellWith: indexPath)
|
||
|
|
cell.frame = CGRect(x: 0, y: 0, width: collectionViewWidth, height: collectionViewHeight)
|
||
|
|
return cell
|
||
|
|
}
|
||
|
|
|
||
|
|
private func getSmallAttributes(indexPath: IndexPath) -> UICollectionViewLayoutAttributes {
|
||
|
|
let cell = UICollectionViewLayoutAttributes(forCellWith: indexPath)
|
||
|
|
cell.frame = getMiniscreenFrame(item: nil)
|
||
|
|
return cell
|
||
|
|
}
|
||
|
|
|
||
|
|
private func getEquallyDividedAttributes(indexPath: IndexPath, item: Int, itemCount: Int, leftDiff: CGFloat) ->
|
||
|
|
UICollectionViewLayoutAttributes {
|
||
|
|
/*-----------------item&page¤tPageItemCount&cell-----------------**/
|
||
|
|
let item = item + 1
|
||
|
|
let page = Int(ceil(CGFloat(item) / CGFloat(kMaxShowCellCount)))
|
||
|
|
let currentPageItemCount = min(itemCount, page * kMaxShowCellCount) - (page - 1) * kMaxShowCellCount // Number of items on the current page
|
||
|
|
let cell = UICollectionViewLayoutAttributes(forCellWith: indexPath)
|
||
|
|
|
||
|
|
/*-----------------currentPageAllRow&beginCellY&beginCellLeft-----------------**/
|
||
|
|
let currentPageAllRow = Int(ceil(CGFloat(currentPageItemCount) / CGFloat(kVideoSeatCellNumberOfOneRow))) // Calculate the total number of rows on this page
|
||
|
|
let itemAllHeight = (itemWidthHeight + itemDiffSpace) * CGFloat(currentPageAllRow) - itemDiffSpace
|
||
|
|
let itemAllWidth = (itemWidthHeight + itemDiffSpace) * kVideoSeatCellNumberOfOneRow - itemDiffSpace
|
||
|
|
let beginCellY = (collectionViewHeight - itemAllHeight) * 0.5 // Calculate beginCellTop
|
||
|
|
let beginCellX = (collectionViewWidth - itemAllWidth) * 0.5 // Calculate beginCellTop
|
||
|
|
let beginCellLeft = CGFloat(page - 1) * collectionViewWidth // Calculate beginCellLeft
|
||
|
|
|
||
|
|
/*-----------------itemIndex&column&row-----------------**/
|
||
|
|
let itemIndex = item - (page - 1) * kMaxShowCellCount // What is the number on this page?
|
||
|
|
let column = (itemIndex - 1) % Int(kVideoSeatCellNumberOfOneRow) // Which column of cell is on the current page starting from 0?
|
||
|
|
let row = Int(ceil(CGFloat(itemIndex) / CGFloat(kVideoSeatCellNumberOfOneRow))) // What is the row of cell on the current page?
|
||
|
|
let itemY = beginCellY + (itemWidthHeight + itemDiffSpace) * CGFloat(row - 1)
|
||
|
|
var itemX = 0.0
|
||
|
|
if currentPageAllRow == row {
|
||
|
|
// Adjust the center of the last row
|
||
|
|
let lastRowItemCount = currentPageItemCount - (row - 1) * Int(kVideoSeatCellNumberOfOneRow)
|
||
|
|
let lastRowBeginCellLeft = (collectionViewWidth - (itemWidthHeight + itemDiffSpace) * CGFloat(lastRowItemCount) - itemDiffSpace) * 0.5
|
||
|
|
itemX = lastRowBeginCellLeft + beginCellLeft + (itemWidthHeight + itemDiffSpace) * CGFloat(column)
|
||
|
|
} else {
|
||
|
|
itemX = beginCellX + beginCellLeft + (itemWidthHeight + itemDiffSpace) * CGFloat(column)
|
||
|
|
}
|
||
|
|
cell.frame = CGRect(x: leftDiff + itemX, y: itemY, width: itemWidthHeight, height: itemWidthHeight)
|
||
|
|
return cell
|
||
|
|
}
|
||
|
|
|
||
|
|
private func getMultipageEquallyDividedAttributes(indexPath: IndexPath, item: Int, itemCount: Int, leftDiff: CGFloat) ->
|
||
|
|
UICollectionViewLayoutAttributes {
|
||
|
|
let item = item + 1
|
||
|
|
let page = Int(ceil(CGFloat(item) / CGFloat(kMaxShowCellCount)))
|
||
|
|
let cell = UICollectionViewLayoutAttributes(forCellWith: indexPath)
|
||
|
|
let currentPageAllRow = kMaxShowCellCount / Int(kVideoSeatCellNumberOfOneRow)
|
||
|
|
let itemAllHeight = (itemWidthHeight + itemDiffSpace) * CGFloat(currentPageAllRow) - itemDiffSpace
|
||
|
|
let itemAllWidth = (itemWidthHeight + itemDiffSpace) * kVideoSeatCellNumberOfOneRow - itemDiffSpace
|
||
|
|
let beginCellY = (collectionViewHeight - itemAllHeight) * 0.5
|
||
|
|
let beginCellX = (collectionViewWidth - itemAllWidth) * 0.5
|
||
|
|
let beginCellLeft = CGFloat(page - 1) * collectionViewWidth
|
||
|
|
let itemIndex = item - (page - 1) * kMaxShowCellCount
|
||
|
|
let column = (itemIndex - 1) % Int(kVideoSeatCellNumberOfOneRow)
|
||
|
|
let row = Int(ceil(CGFloat(itemIndex) / CGFloat(kVideoSeatCellNumberOfOneRow)))
|
||
|
|
let itemY = beginCellY + (itemWidthHeight + itemDiffSpace) * CGFloat(row - 1)
|
||
|
|
let itemX = beginCellX + beginCellLeft + (itemWidthHeight + itemDiffSpace) * CGFloat(column)
|
||
|
|
cell.frame = CGRect(x: leftDiff + itemX, y: itemY, width: itemWidthHeight, height: itemWidthHeight)
|
||
|
|
return cell
|
||
|
|
}
|
||
|
|
}
|