Skip to content

Instantly share code, notes, and snippets.

@PimCoumans
Last active November 13, 2020 14:23
Show Gist options
  • Save PimCoumans/4e77d7d848c849b6cfed49f76cff0ef5 to your computer and use it in GitHub Desktop.
Save PimCoumans/4e77d7d848c849b6cfed49f76cff0ef5 to your computer and use it in GitHub Desktop.
//
// TimelineLayout.swift
// OKVideo
//
// Created by Pim Coumans on 12/11/2020.
// Copyright © 2020 pixelrock. All rights reserved.
//
import UIKit
protocol UICollectionViewTimelineLayoutDelegate: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, durationForClipAtIndexPath indexPath: IndexPath) -> TimeInterval
}
class TimelineLayout: UICollectionViewLayout {
/// Relative offset from center, 1 would be bottom, -1 would be top
var relativeOffset: CGFloat = 0 {
didSet {
invalidateLayout()
}
}
let cellSpacing: CGFloat = 4
let cellHeight: CGFloat = 80
private let minWidth: CGFloat = 40
private let widthPerSecond: Double = 20
private var cache: [UICollectionViewLayoutAttributes] = []
private var contentWidth: CGFloat = 0
override var collectionViewContentSize: CGSize {
CGSize(width: contentWidth, height: cellHeight)
}
override func prepare() {
guard cache.isEmpty, let collectionView = collectionView else {
return
}
var xOffset: CGFloat = 0
let visibleBounds = collectionView.bounds.inset(by: collectionView.adjustedContentInset)
let yCenter = visibleBounds.midY
let yValue = yCenter - (cellHeight / 2)
let yOffset = yCenter + (yValue * relativeOffset) - (cellHeight / 2)
for itemIndex in 0..<collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: itemIndex, section: 0)
let duration = (collectionView.delegate as? UICollectionViewTimelineLayoutDelegate)?.collectionView(collectionView, durationForClipAtIndexPath: indexPath) ?? 0
let frame = CGRect(x: xOffset + cellSpacing,
y: yOffset,
width: max(CGFloat(duration * widthPerSecond), minWidth),
height: cellHeight)
xOffset = frame.maxX
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = frame
cache.append(attributes)
}
contentWidth = xOffset
}
override func invalidateLayout() {
cache.removeAll()
super.invalidateLayout()
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return cache.filter { $0.frame.intersects(rect) }
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cache[indexPath.item]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment