CollectionView 居左对齐(搜索、历史记录)

之前做使用collection做历史记录,不管sollection的怎么设置,item之间能设置最小距离,却不能设置最大距离,所以总是达不到预期效果。后来查看资料重写UICollectionViewFlowLayout方法来达到预期效果。废话不多说,上代码。

未完成效果.png
预期效果.png

一、下面是继承UICollectionViewFlowLayout写的类

import UIKit

extension UICollectionViewLayoutAttributes {

    /** 每行第一个item左对齐 **/
    func leftAlignFrame(sectionInset:UIEdgeInsets) {
        var frame = self.frame
        frame.origin.x = sectionInset.left
        self.frame = frame
    }
}

class UICollectionViewLeftAlignedLayout: UICollectionViewFlowLayout {

    //MARK: - 重新UICollectionViewFlowLayout的方法

    /** Collection所有的UICollectionViewLayoutAttributes */
    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributesToReturn = super.layoutAttributesForElementsInRect(rect)!
        for attributes in attributesToReturn {
            if nil == attributes.representedElementKind {
                let indexPath = attributes.indexPath
                attributes.frame = self.layoutAttributesForItemAtIndexPath(indexPath)!.frame
            }
        }
        return attributesToReturn
    }

    /** 每个item的UICollectionViewLayoutAttributes */
    override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
        //现在item的UICollectionViewLayoutAttributes
        let currentItemAttributes = super.layoutAttributesForItemAtIndexPath(indexPath)!
        //现在section的sectionInset
        let sectionInset = self.evaluatedSectionInset(indexPath.section)
        //是否是section的第一个item
        let isFirstItemInSection = indexPath.item == 0
        //出去section偏移量的宽度
        let layoutWidth: CGFloat = CGRectGetWidth(self.collectionView!.frame) - sectionInset.left - sectionInset.right
        //是section的第一个item
        if isFirstItemInSection {
            //每行第一个item左对齐
            currentItemAttributes.leftAlignFrame(sectionInset)
            return currentItemAttributes
        }
    
        //前一个item的NSIndexPath
        let previousIndexPath = NSIndexPath(forItem: indexPath.item - 1, inSection: indexPath.section)
        //前一个item的frame
        let previousFrame = self.layoutAttributesForItemAtIndexPath(previousIndexPath)!.frame
        //为现在item计算新的left
        let previousFrameRightPoint: CGFloat = previousFrame.origin.x + previousFrame.size.width
        //现在item的frame
        let currentFrame = currentItemAttributes.frame
        //现在item所在一行的frame
        let strecthedCurrentFrame = CGRectMake(sectionInset.left, currentFrame.origin.y, layoutWidth, currentFrame.size.height)
    
        //previousFrame和strecthedCurrentFrame是否有交集,没有,说明这个item和前一个item在同一行,item是这行的第一个item
        let isFirstItemInRow = !CGRectIntersectsRect(previousFrame, strecthedCurrentFrame)
        //item是这行的第一个item
        if isFirstItemInRow {
            //每行第一个item左对齐
            currentItemAttributes.leftAlignFrame(sectionInset)
            return currentItemAttributes
        }
        //不是每行的第一个item
        var frame = currentItemAttributes.frame
        //为item计算新的left = previousFrameRightPoint + item之间的间距
        frame.origin.x = previousFrameRightPoint + self.evaluatedMinimumInteritemSpacing(indexPath.item)
        //为item的frame赋新值
        currentItemAttributes.frame = frame
        return currentItemAttributes
    }

    //MARK: - System

    /** item行间距 **/
    private func evaluatedMinimumInteritemSpacing(ItemAtIndex:Int) -> CGFloat     {
        if let delete = self.collectionView?.delegate {
            weak var delegate = (delete as! UICollectionViewDelegateFlowLayout)
            if delegate!.respondsToSelector(#selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:minimumInteritemSpacingForSectionAtIndex:))) {
                let mini =  delegate?.collectionView!(self.collectionView!, layout: self, minimumInteritemSpacingForSectionAtIndex: ItemAtIndex)
                if mini != nil {
                    return mini!
                }
            }
        }
        return self.minimumInteritemSpacing
    }

    /** section的偏移量 **/
    private func evaluatedSectionInset(itemAtIndex:Int) -> UIEdgeInsets {
        if let delete = self.collectionView?.delegate {
            weak var delegate = (delete as! UICollectionViewDelegateFlowLayout)
            if delegate!.respondsToSelector(#selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:insetForSectionAtIndex:))) {
                let sectionInset =  delegate?.collectionView!(self.collectionView!, layout: self, insetForSectionAtIndex: itemAtIndex)
                if sectionInset != nil {
                    return sectionInset!
                }
            }
        }
        return self.sectionInset
    }
}

下面是OC版本
UICollectionViewLeftAlignedLayout.h

#import <UIKit/UIKit.h>

@interface UICollectionViewLeftAlignedLayout : UICollectionViewFlowLayout

@end

/**
 *  Just a convenience protocol to keep things consistent.
 *  Someone could find it confusing for a delegate object to conform to UICollectionViewDelegateFlowLayout
 *  while using UICollectionViewLeftAlignedLayout.
 */
@protocol UICollectionViewDelegateLeftAlignedLayout <UICollectionViewDelegateFlowLayout>

@end

UICollectionViewLeftAlignedLayout.m

#import "UICollectionViewLeftAlignedLayout.h"

@interface UICollectionViewLayoutAttributes (LeftAligned)

- (void)leftAlignFrameWithSectionInset:(UIEdgeInsets)sectionInset;

@end

@implementation UICollectionViewLayoutAttributes (LeftAligned)

/** 每行第一个item左对齐 **/
- (void)leftAlignFrameWithSectionInset:(UIEdgeInsets)sectionInset
{
    CGRect frame = self.frame;
    frame.origin.x = sectionInset.left;
    self.frame = frame;
}

@end


@implementation UICollectionViewLeftAlignedLayout

#pragma mark - UICollectionViewLayout

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
    for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
        if (nil == attributes.representedElementKind) {
            NSIndexPath* indexPath = attributes.indexPath;
            attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
        }
    }
    return attributesToReturn;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    //现在item的UICollectionViewLayoutAttributes
    UICollectionViewLayoutAttributes* currentItemAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
    //现在section的sectionInset
    UIEdgeInsets sectionInset = [self evaluatedSectionInsetForItemAtIndex:indexPath.section];

    //是否是section的第一个item
    BOOL isFirstItemInSection = indexPath.item == 0;
    //出去section偏移量的宽度
    CGFloat layoutWidth = CGRectGetWidth(self.collectionView.frame) - sectionInset.left - sectionInset.right;

    //是section的第一个item
    if (isFirstItemInSection) {
        //每行第一个item左对齐
        [currentItemAttributes leftAlignFrameWithSectionInset:sectionInset];
        return currentItemAttributes;
    }

    //前一个item的NSIndexPath
    NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
    //前一个item的frame
    CGRect previousFrame = [self layoutAttributesForItemAtIndexPath:previousIndexPath].frame;
    //为现在item计算新的left
    CGFloat previousFrameRightPoint = previousFrame.origin.x + previousFrame.size.width;
    //现在item的frame
    CGRect currentFrame = currentItemAttributes.frame;
    //现在item所在一行的frame
    CGRect strecthedCurrentFrame = CGRectMake(sectionInset.left,
                                              currentFrame.origin.y,
                                              layoutWidth,
                                              currentFrame.size.height);
    //previousFrame和strecthedCurrentFrame是否有交集,没有,说明这个item和前一个item在同一行,item是这行的第一个item
    BOOL isFirstItemInRow = !CGRectIntersectsRect(previousFrame, strecthedCurrentFrame);

    //item是这行的第一个item
    if (isFirstItemInRow) {
        //每行第一个item左对齐
        [currentItemAttributes leftAlignFrameWithSectionInset:sectionInset];
        return currentItemAttributes;
    }

    //不是每行的第一个item
    CGRect frame = currentItemAttributes.frame;
    //为item计算新的left = previousFrameRightPoint + item之间的间距
    frame.origin.x = previousFrameRightPoint + [self evaluatedMinimumInteritemSpacingForItemAtIndex:indexPath.row];
    //为item的frame赋新值
    currentItemAttributes.frame = frame;
    return currentItemAttributes;
}

/** item行间距 **/
- (CGFloat)evaluatedMinimumInteritemSpacingForItemAtIndex:(NSInteger)index
{
    if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) {
        id<UICollectionViewDelegateLeftAlignedLayout> delegate = (id<UICollectionViewDelegateLeftAlignedLayout>)self.collectionView.delegate;

        return [delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:index];
    } else {
        return self.minimumInteritemSpacing;
    }
}

/** section的偏移量 **/
- (UIEdgeInsets)evaluatedSectionInsetForItemAtIndex:(NSInteger)index
{
    if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
        id<UICollectionViewDelegateLeftAlignedLayout> delegate = (id<UICollectionViewDelegateLeftAlignedLayout>)self.collectionView.delegate;

        return [delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:index];
    } else {
        return self.sectionInset;
    }
}

@end

二、下面在collectionView中使用这个类,我的collectionView是使用xib创建的。

/// 搜索记录
@IBOutlet weak var collectionView: UICollectionView!
/// 历史搜索类型
var historyArray = [String]()

override func awakeFromNib() {
    super.awakeFromNib()

    historyArray = ["关键词","iOS学习基础","牛奶","跳绳","轮滑鞋","香蕉","面包","苹果梨","苹果"]

    let layout = UICollectionViewLeftAlignedLayout()
    //竖向cell之间的距离
    layout.minimumLineSpacing = 15
    //横向cell之间的距离,没有设置0.0
    layout.minimumInteritemSpacing = 10
    //section的header的大小
    layout.headerReferenceSize = CGSizeMake(ScreenWidth , 44);
    //section的偏移量
    layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10)
    //collectionView的偏移量
    collectionView.contentInset = UIEdgeInsetsMake(0, 0, 5, 0)
    //SearchCell:xib中item的identifier
    collectionView.registerNib(UINib.init(nibName: "SearchCell", bundle: nil), forCellWithReuseIdentifier: "SearchCell")
    //SearchHeaderView中sender的header的identifier
    collectionView.registerNib(UINib.init(nibName: "SearchHeaderView", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "SearchHeaderView")
    collectionView.collectionViewLayout = layout
}

//MARK: - UICollectionViewDataSource

/** Section数 */
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int{
    if historyArray.count > 0 {
        return 1
    }
    return 0
}

/** Items数 */
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return historyArray.count
}

/** Items创建 */
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell{
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("SearchCell", forIndexPath: indexPath) as? SearchCell
    cell?.name.text = historyArray[indexPath.item]
    return cell!
}

/** collection的header创建 */
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
    let view = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "SearchHeaderView", forIndexPath: indexPath) as? SearchHeaderView
    return view!
}

//MARK: - UICollectionViewDelegate

/** 历史记录关键词点击 */
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
   
}

//MARK: - UICollectionViewDelegateFlowLayout

/** 设置关键词大小 */
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    let name = historyArray[indexPath.item]
    let size = self.boundingRectWithSize(CGSizeMake(ScreenWidth - 20, 30), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: UIFont.systemFontOfSize(12)], context: nil).size
    let with = size.width
    return CGSizeMake(with + 40, 30)
}

参考文档
http://code.cocoachina.com/view/126206

end:小编是很认真的写文哦,如果小编的文对您有用,一定要点“喜欢”哦!如果有问题欢迎评论

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 小时候,爷爷奶奶似乎是在吵骂中过日子。印象最深的一次是每天晚上奶奶会给爷爷烧一锅奶茶,有一天爷爷说奶奶这次烧的不好...
    Taylor記阅读 194评论 0 0
  • 年年说:这是一本学习外语的方法论集锦,对于外语学习困难户尤其值得一读。 我的学生史如果要加上一个有关外语学习方面的...
    汝年年阅读 1,926评论 14 39
  • 今天上午,万达商业、融创中国联合发布公告:融创中国以295.75亿元收购了13个万达文旅城的项目股权,并以335....
    恻隐之心_6bfd阅读 175评论 0 0
  • 你对夏天有什么美好的印象?是竹席、折扇、半杯清茶,还是微风,鸣蝉,十里荷香?每个人都有自己的答案,古人也一样,在诗...
    杨三岁阿阅读 422评论 0 3