美文网首页
Swift 自定义 UICollectionViewFlowLa

Swift 自定义 UICollectionViewFlowLa

作者: ShineYangGod | 来源:发表于2020-05-18 17:01 被阅读0次

    需求

    在当前的移动端开发中,我们经常可以看见集合视图需要横向布局分页的场景。例如:

    微信的表情

    图1

    美团外卖的首页

    图2

    需求实现分析

    //预布局方法 布局相关代码可放在此处
        override func prepare() {
        }
    
        /**
        返回true只要显示的边界发生改变就重新布局:(默认是false)   
        内部会重新调用prepareLayout和调用
       layoutAttributesForElementsInRect方法获得部分cell的布局属性
        */
    
        override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
            return true;
        }
        /*
        根据indexPath去对应的UICollectionViewLayoutAttributes  这个是取值的,要重写,在移动删除的时候系统会调用改方法重新去UICollectionViewLayoutAttributes然后布局
         */
    
        override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
            return super.layoutAttributesForItem(at: indexPath);
        }
    
        //返回当前的ContentSize
         override open var collectionViewContentSize: CGSize {
    
            return CGSize(width: (self.collectionView?.width)! * CGFloat(self.collectionView!.numberOfSections), height: self.collectionView!.height);
        }
    
        // 返回所有的布局属性
         override func layoutAttributesForElements(in rect: CGRect) ->[UICollectionViewLayoutAttributes]? {
             return super.layoutAttributesForElements(in: rect);
          }
    
    

    整体代码

    mport UIKit
    
    class SYCollectionViewLayout: UICollectionViewFlowLayout {
    
    
        var numRow:Int = 0;//行数
        var numCol:Int = 0;//列数
        var contentInsets: UIEdgeInsets =  UIEdgeInsetsMake(0, 0, 0, 0)
        //所有cell的布局属性
        var layoutAttributes: [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]();
    
        override init() {
            super.init();
            self.itemSize = CGSize(width: 50, height: 50);  //这里可以根据自己的需求设置大小
            self.scrollDirection = .horizontal
            self.numRow = 7;
            self.numCol = 4;
            self.contentInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
    
        }
    
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
    
        //计算布局
        override func prepare() {
    
        let numsection = self.collectionView!.numberOfSections;
        let itemNum: Int = self.collectionView!.numberOfItems(inSection: 0)
            layoutAttributes.removeAll();
            for i in 0..<numsection{
                for j in 0..<itemNum{
                    let layout = self.layoutAttributesForItem(at: IndexPath(item: j, section: i))!;
                    self.layoutAttributes.append(layout);
                }
            }
    
        }
    
        /**
         返回true只要显示的边界发生改变就重新布局:(默认是false)
         内部会重新调用prepareLayout和调用
         layoutAttributesForElementsInRect方法获得部分cell的布局属性
         */
    
        override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
            return true;
        }
        /*
        根据indexPath去对应的UICollectionViewLayoutAttributes  这个是取值的,要重写,在移动删除的时候系统会调用改方法重新去UICollectionViewLayoutAttributes然后布局
         */
        override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    
     assert((self.collectionView!.width-self.contentInsets.left - self.contentInsets.right) >= (self.itemSize.width*CGFloat(self.numRow)), "布局宽度不能超过父试图宽度")
    
            assert((self.collectionView!.height-self.contentInsets.top - self.contentInsets.bottom) >= self.itemSize.height*CGFloat(self.numCol), "布局高度不能超过父视图高度")     
    
            let layoutAttribute = super.layoutAttributesForItem(at: indexPath);
    
            //计算水平距离
            let hor_spacing = (self.collectionView!.width - CGFloat(self.numRow) * self.itemSize.width - self.contentInsets.left - self.contentInsets.right) / CGFloat(self.numRow - 1);
    
          //计算垂直距离
            let ver_spacing = (self.collectionView!.height - CGFloat(self.numCol) * self.itemSize.height - self.contentInsets.top - self.contentInsets.bottom) / CGFloat(self.numCol - 1);
    
            //计算x的位置
            var frame_x = CGFloat(indexPath.section) * self.collectionView!.width + CGFloat(indexPath.row%self.numRow) * self.itemSize.width + self.contentInsets.left;
           frame_x += (hor_spacing*(CGFloat(indexPath.row%self.numRow)));
    
    
    
            //计算y的位置
            var frame_y = CGFloat((indexPath.row/self.numRow)) * self.itemSize.height + self.contentInsets.top;
    
            frame_y += (ver_spacing*CGFloat(indexPath.row/self.numRow));
    
            layoutAttribute?.frame = CGRect(x:frame_x, y:frame_y, width: self.itemSize.width, height: self.itemSize.height);
    
            return layoutAttribute;
    
        }
    
        override open var collectionViewContentSize: CGSize {
    
            return CGSize(width: (self.collectionView?.width)! * CGFloat(self.collectionView!.numberOfSections), height: self.collectionView!.height);
        }
    
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    
           return self.layoutAttributes
        }
    
    
    }
    

    使用

      let collectionView = UICollectionView(frame: M_RECT(0, y: NEWHEIGHT(0), w: kScreenW, h: kScreenH - 64 - NEWHEIGHT(0)), collectionViewLayout: SYCollectionViewLayout());
      collectionView.delegate = self;
      collectionView.dataSource = self;
    
    
     /**
         返回每个分组有几个数据
         */
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
    
            return 32;
        }
        /**
         返回有几个分组
         */
        func numberOfSections(in collectionView: UICollectionView) -> Int
        {
    
            return 2;
        }
    
    在实际使用的过程中 布局的行数、列数等均可以根据实际需求自定义。

    相关文章

      网友评论

          本文标题:Swift 自定义 UICollectionViewFlowLa

          本文链接:https://www.haomeiwen.com/subject/snqpohtx.html