我想知道如何才能在UICollectionView
内实现平滑缩放,到目前为止我已经迈出了第一步 - 它放大/缩小但是没有更好的控制我的值{I}我想阻止它。
这是我放大/缩小的实现:
默认缩放lvl。
编辑
改进了缩放algorythm。
var lastZoomLvl: CGFloat = 1 {
willSet(newValue) {
self.lastZoomLvl = newValue
}
}
// Zooming logic.
func zoom(scale: CGFloat) {
if scale > 1 {
lastZoomLvl += scale
} else {
lastZoomLvl -= scale
}
if lastZoomLvl < 1 {
lastZoomLvl = 1
} else if lastZoomLvl > 12 {
lastZoomLvl = 12
}
flowLayout.zoomMultiplier = lastZoomLvl
}
zoom
方法的调用位于VC
UICollectionView
。{/ p>
func zoom(_ gesture: UIPinchGestureRecognizer) {
let scale = gesture.scale
if gesture.state == .began {
chartCollectionView.isScrollEnabled = false
}
if gesture.state == .ended {
chartCollectionView.isScrollEnabled = true
if scale > 1 {
self.chart.lastZoomLvl += scale
}
}
chartCollectionView.performBatchUpdates({
self.chart.zoom(scale: scale)
}, completion: { _ in
// TODO: Maybe something in the future ?
})
}
正如您所见,我通过添加UIPinchGestureRecognizer
然后使用performBatchUpdates
来实现缩放,我的布局将按新的单元格大小进行更新。
布局实施:
class ChartCollectionViewFlowLayout: UICollectionViewFlowLayout {
private var cellAttributes = [UICollectionViewLayoutAttributes]()
private var supplementaryAttributes = [UICollectionViewLayoutAttributes]()
private var newIndexPaths = [IndexPath]()
private var removedIndexPaths = [IndexPath]()
private let numberOfSections = 5
private var suplementaryWidth: CGFloat = 0
private let horizontalDividerHeight: CGFloat = 1
private var timeLineHeight: CGFloat = 0
fileprivate var contentSize: CGSize?
static let numberOfVisibleCells: Int = 4
// Calculate the width available for time entry cells.
var itemsWidth: CGFloat = 0 {
willSet(newValue) {
self.itemsWidth = newValue
}
}
var cellWidth: CGFloat = 0 {
willSet(newValue) {
self.cellWidth = newValue
}
}
var numberOfCells: Int = 24 {
willSet(newValue) {
self.numberOfCells = newValue
}
}
var zoomMultiplier: CGFloat = 1 {
willSet(newValue) {
self.zoomMultiplier = newValue
}
}
override init() {
super.init()
scrollDirection = .horizontal
sectionHeadersPinToVisibleBounds = true
sectionFootersPinToVisibleBounds = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func invalidateLayout() {
super.invalidateLayout()
supplementaryAttributes.removeAll()
cellAttributes.removeAll()
}
override func prepare() {
if collectionView == nil { return }
var cellX: CGFloat = 0
var rowY: CGFloat = 0
let xOffset = collectionView!.contentOffset.x
// Calculate the height of a row.
let availableHeight = collectionView!.bounds.height - collectionView!.contentInset.top - collectionView!.contentInset.bottom - CGFloat(numberOfSections - 1) * horizontalDividerHeight
if deviceIdiom == .pad {
suplementaryWidth = 75
timeLineHeight = 30
} else {
suplementaryWidth = 30
timeLineHeight = 25
}
itemsWidth = collectionView!.bounds.width - collectionView!.contentInset.left - collectionView!.contentInset.right - suplementaryWidth
var rowHeight = availableHeight / CGFloat(numberOfSections)
let differenceBetweenTimeLine = rowHeight - timeLineHeight
let toAddToRowY = differenceBetweenTimeLine / CGFloat(numberOfSections - 1)
rowHeight += toAddToRowY
// For each section.
for i in 0..<numberOfSections {
// Generate and store layout attributes header cell.
let headerIndexPath = IndexPath(item: 0, section: i)
let headerCellAttributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, with: headerIndexPath)
supplementaryAttributes.append(headerCellAttributes)
if i == 0 {
rowY = CGFloat(i) * (30 + horizontalDividerHeight)
headerCellAttributes.frame = CGRect(x: 0, y: rowY, width: suplementaryWidth, height: timeLineHeight)
} else {
rowY = CGFloat(i) * (rowHeight + horizontalDividerHeight) - (toAddToRowY * CGFloat(numberOfSections))
headerCellAttributes.frame = CGRect(x: 0, y: rowY, width: suplementaryWidth, height: rowHeight)
}
// Sticky header / footer while scrolling.
headerCellAttributes.zIndex = 1
headerCellAttributes.frame.origin.x = xOffset
// Set the initial X position for cell.
cellX = suplementaryWidth
// For each cell set a width.
for j in 0..<numberOfCells {
//Get the width of the cell.
cellWidth = CGFloat(Double(itemsWidth) / Double(numberOfCells)) * zoomMultiplier
// Generate and store layout attributes for the cell
let cellIndexPath = IndexPath(item: j, section: i)
let entryCellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndexPath)
cellAttributes.append(entryCellAttributes)
if i == 0 {
entryCellAttributes.frame = CGRect(x: cellX, y: rowY, width: cellWidth, height: timeLineHeight)
} else {
entryCellAttributes.frame = CGRect(x: cellX, y: rowY, width: cellWidth, height: rowHeight)
}
cellX += cellWidth
}
}
contentSize = CGSize(width: cellX, height: collectionView!.bounds.height)
super.prepare()
}
override var collectionViewContentSize: CGSize {
get {
if contentSize != nil {
return contentSize!
}
return .zero
}
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttributes.first(where: { (attributes) -> Bool in
return attributes.indexPath == indexPath
})
}
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return supplementaryAttributes.first(where: { (attributes) -> Bool in
return attributes.indexPath == indexPath
})
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributes = [UICollectionViewLayoutAttributes]()
for attribute in supplementaryAttributes {
if attribute.frame.intersects(rect) {
attributes.append(attribute)
}
}
for attribute in cellAttributes {
if attribute.frame.intersects(rect) {
attributes.append(attribute)
}
}
return attributes
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
布局允许我将粘性标题放在左侧,单元格大小由cellWidth
定义。我认为尺寸呈指数级增长,我怎样才能获得更好的控制?有没有人有想法我怎么能证明它?
提前致谢!