Last active
November 13, 2020 14:23
-
-
Save PimCoumans/4e77d7d848c849b6cfed49f76cff0ef5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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