代码之家  ›  专栏  ›  技术社区  ›  TruMan1

如何将水平分页与应用商店等多行集合视图对齐?

  •  9
  • TruMan1  · 技术社区  · 7 年前
    override func viewdidload()。{
    
    )
    
    
    类多行布局:uiCollectionViewFlowLayout{
    
    便利初始化(行数:cgfloat,间距:cgfloat)?=nil,插入:cgloat?=零){
    
    self.minimumInteritemspacking=0
    
    如果让间距=间距{
    }
    
    self.sectioninset=uiedgeinset(上:0,左:inset,下:0,右:inset)
    }
    
    超级。准备()
    
    self.itemsize=计算项大小(来自:collectionview.bounds.size)
    
    guard let collectionview=集合视图,
    返回false
    
    返回true
    }
    
    
    返回cgsize(
    高度:bounds.height/rowscount
    }
    
    
    

    我有一个正在工作的snap paging functionality是否可以有人帮助将快照分页用于分组行而不是每页一个项目?

    override func viewDidLoad() {
        super.viewDidLoad()
    
        collectionView.collectionViewLayout = MultiRowLayout(
            rowsCount: 3,
            inset: 16
        )
    }
    
    ...
    
    class MultiRowLayout: UICollectionViewFlowLayout {
        private var rowsCount: CGFloat = 0
    
        convenience init(rowsCount: CGFloat, spacing: CGFloat? = nil, inset: CGFloat? = nil) {
            self.init()
    
            self.scrollDirection = .horizontal
            self.minimumInteritemSpacing = 0
            self.rowsCount = rowsCount
    
            if let spacing = spacing {
                self.minimumLineSpacing = spacing
            }
    
            if let inset = inset {
                self.sectionInset = UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset)
            }
        }
    
        override func prepare() {
            super.prepare()
    
            guard let collectionView = collectionView else { return }
            self.itemSize = calculateItemSize(from: collectionView.bounds.size)
        }
    
        override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
            guard let collectionView = collectionView,
                !newBounds.size.equalTo(collectionView.bounds.size) else {
                    return false
            }
    
            itemSize = calculateItemSize(from: collectionView.bounds.size)
            return true
        }
    }
    
    private extension MultiRowLayout {
    
        func calculateItemSize(from bounds: CGSize) -> CGSize {
            return CGSize(
                width: bounds.width - minimumLineSpacing * 2 - sectionInset.left,
                height: bounds.height / rowsCount
            )
        }
    }
    

    isPagingEnabledUICollectionView只有当集合视图的单元格宽度为100%时才有效,这样用户就不会看到前一个单元格和下一个单元格。

    snap paging functionality

    2 回复  |  直到 7 年前
        1
  •  14
  •   rob mayoff    7 年前

    uicollectionview uiscrollview 的子类,因此其委托协议 uicollectionview delegate uiscrollviewdelegate 的子类型。这意味着您可以在集合视图委托中实现任何 uiscrollviewdelegate s方法。

    下面是一个示例实现:

    let bounds=scrollview.bounds //这是允许的最大ContentOffset.x。将其作为contentoffset.x,单元格最后一列的右边缘位于集合视图框架的右边缘。 设x=poses.min(按:abs($0.center.x-xcenter)<abs($1.center.x-xcenter))?.frame.origin.x??0个 }否则,如果速度为.x>0{ //找到当前位置之外最左边的列。 }其他{ 设x=poses.max(by:$0.center.x<$1.center.x)?.frame.origin.x??0个 //速度是以每毫秒点为单位测量的。
    
    
    
    

    您可以在这里找到我的测试项目的完整源代码:https://github.com/mayoff/multilrowsnapper

    UIScrollViewUICollectionViewDelegateUIScrollViewDelegate.这意味着您可以实现集合视图委托中的方法。

    scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)将目标内容偏移舍入到最近单元格列的左上角。

    override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        let layout = collectionViewLayout as! UICollectionViewFlowLayout
        let bounds = scrollView.bounds
        let xTarget = targetContentOffset.pointee.x
    
        // This is the max contentOffset.x to allow. With this as contentOffset.x, the right edge of the last column of cells is at the right edge of the collection view's frame.
        let xMax = scrollView.contentSize.width - scrollView.bounds.width
    
        if abs(velocity.x) <= snapToMostVisibleColumnVelocityThreshold {
            let xCenter = scrollView.bounds.midX
            let poses = layout.layoutAttributesForElements(in: bounds) ?? []
            // Find the column whose center is closest to the collection view's visible rect's center.
            let x = poses.min(by: { abs($0.center.x - xCenter) < abs($1.center.x - xCenter) })?.frame.origin.x ?? 0
            targetContentOffset.pointee.x = x
        } else if velocity.x > 0 {
            let poses = layout.layoutAttributesForElements(in: CGRect(x: xTarget, y: 0, width: bounds.size.width, height: bounds.size.height)) ?? []
            // Find the leftmost column beyond the current position.
            let xCurrent = scrollView.contentOffset.x
            let x = poses.filter({ $0.frame.origin.x > xCurrent}).min(by: { $0.center.x < $1.center.x })?.frame.origin.x ?? xMax
            targetContentOffset.pointee.x = min(x, xMax)
        } else {
            let poses = layout.layoutAttributesForElements(in: CGRect(x: xTarget - bounds.size.width, y: 0, width: bounds.size.width, height: bounds.size.height)) ?? []
            // Find the rightmost column.
            let x = poses.max(by: { $0.center.x < $1.center.x })?.frame.origin.x ?? 0
            targetContentOffset.pointee.x = max(x, 0)
        }
    }
    
    // Velocity is measured in points per millisecond.
    private var snapToMostVisibleColumnVelocityThreshold: CGFloat { return 0.3 }
    

    demo

    您可以在这里找到我的测试项目的完整源代码:https://github.com/mayoff/multiRowSnapper

        2
  •  1
  •   RGhate    7 年前

    collectionview.ispagingenagenabled=真

    如果此属性的值为true,则当用户滚动时,滚动视图将在滚动视图边界的倍数处停止。默认值为假。

    例如,CollectionView?.contentinset=uiedgeinsetmake(0、0、0、0)