UICollectionView靠左显示的Layout代码(swift)

屏幕快照 2019-07-09 下午6.15.57.png

实现如上效果

layout

import UIKit

protocol UICollectionViewDelegateLeftAlignedLayout: UICollectionViewDelegateFlowLayout {
    
}

extension UICollectionViewLayoutAttributes {
    func leftAlignFrame(with sectionInset: UIEdgeInsets) {
        var frame = self.frame
        frame.origin.x = sectionInset.left
        self.frame = frame
    }
}

class LCYSearchFlowLayout: UICollectionViewFlowLayout {

    //layoutAttributesForElementsInRect方法 ---------------
    /*
     rect初始的layout的外观将由该方法返回的UICollectionViewLayoutAttributes来决定。
     返回在collectionView的可见范围内(bounds)所有item对应的layoutAttrure对象装成的数组。collectionView的每个item都对应一个专门的UICollectionViewLayoutAttributes类型的对象来表示该item的一些属性,比如bounds,size,transform,alpha等。
     */
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let originalAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
        let updatedAttributes = NSMutableArray.init(array: originalAttributes)
        
        for attribute in originalAttributes {
            /*
             @property(nonatomic, readonly) UICollectionElementCategory representedElementCategory;
             Item的类型。
             你可以使用这个属性的值来区分这个布局属性是用于一个Cell还是Supplementary View还是Decoration View。
             
             
             @property(nonatomic, readonly) NSString *representedElementKind;
             目标视图的布局指定标识符。
             你可以使用这个属性的值来标识Supplementary View或者Decoration View相关联的属性给定的目的。如果representedElementCategory属性为UICollectionElementCategoryCell,那么这个属性为nil。
             */
            if (attribute.representedElementKind == nil) {
                let index = updatedAttributes.index(of: attribute)
                //layoutAttributesForItemAtIndexPath:返回对应于indexPath的位置的cell的布局属性,这个方法被重写了
                updatedAttributes[index] = self.layoutAttributesForItem(at: attribute.indexPath) as Any
            }
        }
        
        return (updatedAttributes as! [UICollectionViewLayoutAttributes])
    }
    
    //重写了
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        
        //当前的UICollectionViewLayoutAttributes
        let currentItemAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as! UICollectionViewLayoutAttributes

        let sectionInset = self.evaluatedSectionInsetForItem(at: indexPath.section)
        
        let isFirstItemInSection: Bool = indexPath.item == 0
        //如果是第一个那就直接返回就行
        if isFirstItemInSection {
            currentItemAttributes.leftAlignFrame(with:sectionInset)
            return currentItemAttributes
        }
        
        let layoutWidth: CGFloat = (self.collectionView?.frame.size.width)! - sectionInset.left - sectionInset.right
        
        let previousIndexPath = NSIndexPath.init(item: indexPath.item - 1, section: indexPath.section)
        
        let previousFrame = self.layoutAttributesForItem(at: previousIndexPath as IndexPath)?.frame
        
        let previousFrameRightPoint = (previousFrame?.origin.x)! + previousFrame!.size.width
        
        let currentFrame = currentItemAttributes.frame
        
        let strecthedCurrentFrame = CGRect(x: sectionInset.left, y: currentFrame.origin.y, width: layoutWidth, height: currentFrame.size.height)
        
        //如果不想交说明是这一行的第一个
        let isFirstItemInRow = !previousFrame!.intersects(strecthedCurrentFrame)
        
        if isFirstItemInRow {
            currentItemAttributes.leftAlignFrame(with: sectionInset)
            return currentItemAttributes
        }
        
        //放到之前的item的右侧
        
        var frame = currentItemAttributes.frame
        frame.origin.x = previousFrameRightPoint + self.evaluatedMinimumInteritemSpacingForSection(at: indexPath.section)
        
        currentItemAttributes.frame = frame
        
        return currentItemAttributes
        
    }
    
    // 计算section的inset
    func evaluatedSectionInsetForItem(at index: NSInteger) -> UIEdgeInsets {

        if (self.collectionView?.delegate?.responds(to: #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:insetForSectionAt:))))! {
            
            let delegate = self.collectionView?.delegate as! UICollectionViewDelegateLeftAlignedLayout
            
            return (delegate.collectionView?(self.collectionView!, layout: self, insetForSectionAt: index))!
            
        } else {
            return sectionInset
        }
        
    }
    
    func evaluatedMinimumInteritemSpacingForSection(at index: NSInteger) -> CGFloat {
        if (self.collectionView?.delegate?.responds(to: #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:minimumInteritemSpacingForSectionAt:))))! {
            let delegate = self.collectionView?.delegate as! UICollectionViewDelegateFlowLayout
            return (delegate.collectionView?(self.collectionView!, layout: self, minimumInteritemSpacingForSectionAt: index))!
        } else {
            return self.minimumInteritemSpacing
        }
    }
    
}

根据文字计算宽高

    func settingCollectionViewItemWidthBounding(with text: String) -> CGSize {
        let sizeWidth = CGSize(width: CGFloat(MAXFLOAT), height: 20)
        let sizeHeight = CGSize(width: screenWidth - 40, height: CGFloat(MAXFLOAT))
        
        let attributeDic = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14)]
        let frameWidth = text.boundingRect(with: sizeWidth, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributeDic, context: nil)
        
        let frameHeight = text.boundingRect(with: sizeHeight, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributeDic, context: nil)
        
        var finalSize = CGSize(width: frameWidth.size.width + 21, height: 30)
        
        if frameWidth.size.width > screenWidth - 40 {
            finalSize = CGSize(width: screenWidth - 40, height: frameHeight.size.height + 10)
        }
        
        return finalSize
        
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353