之前做使用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:小編是很認真的寫文哦,如果小編的文對您有用,一定要點“喜歡”哦!如果有問題歡迎評論