平滑的可缩放集合视图

时间:2017-08-17 12:33:43

标签: swift swift3 uicollectionview

我想知道如何才能在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定义。我认为尺寸呈指数级增长,我怎样才能获得更好的控制?有没有人有想法我怎么能证明它?

提前致谢!

0 个答案:

没有答案