Swift 自定义 UICollectionViewFlowLa
2020-05-18 本文已影响0人
ShineYangGod
需求
在当前的移动端开发中,我们经常可以看见集合视图需要横向布局分页的场景。例如:
微信的表情
图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;
}