本文重点记录使用collectionView做应用管理、瀑布流、图片轮播器,代码下载地址:http://download.csdn.net/download/jacob_ios/9411733
1.使用storyboard
2.使用xib
3.纯代码实现
UIImageView *imgView=[[UIImageView alloc]init];
//从父容器获取子控件
imgView=cell.contentView.subviews[0];
XYappData *data=self.arr[indexPath.item];
imgView.image=[UIImage imageNamed:data.icon];
UILabel *lab=[[UILabel alloc]init];
lab=cell.contentView.subviews[2];
lab.text=data.name;
return cell;
//instantiateWithOwner可以读取指定的xib文件,将xib文件中所有的view返回存储到数组中,同时设置top view
HMAppCell *cell=[[nib instantiateWithOwner:self options:nil] lastObject];
//设置布局属性
self.layout.itemSize=CGSizeMake(cell.frame.size.width, cell.frame.size.height);
//1.名称:区分大小写,不要扩展名
//2.如果是nil,则默认就是mainBundle
//UINib *nib=[UINib nibWithNibName:@"HMAppCell" bundle:[NSBundle mainBundle]];
UINib *nib=[UINib nibWithNibName:@"HMAppCell" bundle:nil];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:@"app"];
//**********************881.找缓存cell
//2.如果没有缓存cell,就去找原型cell
HMAppCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"app" forIndexPath:indexPath];
cell.app=self.apps[indexPath.item];
return cell;
//设置头部和底部view--只有实现这个方法才能够正常的显示头部和底部
//什么时候调用这个方法:当你当前的视图能够看到头部view或者底部view的时候就会调用这个方法来创建头部或者底部view
//并不是一开始就创建好
- (UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
NSString *ID=@"header";
if (kind==UICollectionElementKindSectionFooter) {
ID=@"footer";
}
UICollectionReusableView *userView=[collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:ID
forIndexPath:indexPath];
//NSLog(@"%@",kind);
return userView;
}
关键点:
1.设置底部视图的时候,需要点是把footer进行封装,有利于对其控制,
//设置底部视图
-(UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
XYshopFooter *footer=nil;
if (kind==UICollectionElementKindSectionFooter) {
footer=[collectionView dequeueReusableSupplementaryViewOfKind: kind withReuseIdentifier:@"footer" forIndexPath:indexPath];
// NSLog(@"footer");
//让菊花开始转动
[footer.grayView startAnimating];
//延迟操作,加载数据,
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//加载
[self loadData];
//刷新界面
[self.collectionView reloadData];
});
return footer;
}
return nil;
}
//懒加载
-(NSMutableArray *)arr{
if (_arr==nil) {
_arr=[NSMutableArray array];
}
return _arr;
}
//
-(void)loadData{
NSMutableArray *arrM=[XYshoping arr:self.index];
self.index++;
[self.arr addObjectsFromArray:arrM];
}
注意:在生成底部视图的时候,需要在下次加载之前删除一个footer ,不然会出现两个footer
将i改为从self.attArr.count开始,可以避免在数据刷新的时候上次的数据为空
若实现全部的自动布局,将self.attArr.count清空,并在此从0开始布局,这样在换屏的时候可以从新布局,实现效果
@interface XYlayout()
//存储cell的frame值的数组
@property(nonatomic,strong)NSMutableArray *attArr;
//存储每一列的
@property(nonatomic,strong)NSMutableDictionary *mutYDic;
@end
@implementation XYlayout
-(NSMutableArray *)attArr{
if (_attArr==nil) {
_attArr=[NSMutableArray array];
}
return _attArr;
}
//初始化Y值,从顶部的位置开始
-(NSMutableDictionary *)mutYDic{
if (_mutYDic==nil) {
_mutYDic=[NSMutableDictionary dictionary];
for (int i=0; i<self.countLine; i++) {
NSString *key=[NSString stringWithFormat:@"%d",i];
_mutYDic[key]=@(self.sectionInset.top);
}
}
return _mutYDic;
}
//每次布局的时候调用该方法
-(void)prepareLayout{
NSLog(@"preparelayout");
//删除底部的值,不然会出现两个footer
[self.attArr removeLastObject];
NSInteger total=[self.collectionView numberOfItemsInSection:0];
//将i改为从self.attArr.count开始,可以避免在数据刷新的时候上次的数据为空
//若实现全部的自动布局,将self.attArr.count清空,并在此从0开始布局
self.mutYDic=nil;
for (NSInteger i=0; i<total; i++) {
//确定某个位置上
NSIndexPath *path=[NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *att=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
//计算宽
CGFloat width=(self.collectionView.bounds.size.width-self.sectionInset.left-self.sectionInset.right-self.minimumInteritemSpacing*(self.countLine-1))/(self.countLine);
//计算高,代理实现
// XYshoping *shop=self.shop[i];
// CGFloat height=(width*shop.height)/shop.width;
CGFloat height= [self.delegate heightForIndex:i withWidth:width];
//计算X
// CGFloat x=self.sectionInset.left+(width+self.minimumInteritemSpacing)*(i%self.countLine);
NSString *minCol=[self minCol];
CGFloat x=self.sectionInset.left+(width+self.minimumInteritemSpacing)*[minCol floatValue];
//计算Y
// NSString *col=[NSString stringWithFormat:@"%ld",i%self.countLine];
CGFloat y=[self.mutYDic[minCol] floatValue];
att.frame=CGRectMake(x, y, width, height);
//重置y
// y=[@(y+height+self.minimumLineSpacing) floatValue];
self.mutYDic[minCol]=@(y+height+self.minimumLineSpacing);
//将att加入到数组中
[self.attArr addObject:att];
}
//设置底部frame值
NSIndexPath *path=[NSIndexPath indexPathForItem:0 inSection:0];
UICollectionViewLayoutAttributes *footer=[UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:path];
NSString *maxCol=[self maxCol];
footer.frame=CGRectMake(0, [self.mutYDic[maxCol] floatValue], self.collectionView.bounds.size.width, self.footerReferenceSize.height);
[self.attArr addObject:footer];
}
//确定滚动的范围
-(CGSize)collectionViewContentSize{
NSString *maxCol=[self maxCol];
CGSize size=CGSizeMake(self.collectionView.bounds.size.width, [self.mutYDic[maxCol] floatValue]+self.footerReferenceSize.height);
return size;
}
//比较最大的Y值
-(NSString*)maxCol{
NSString *maxCol=@"0";
for (int i=0; i<self.countLine; i++) {
NSString *col=[NSString stringWithFormat:@"%d",i];
if ([self.mutYDic[col] floatValue]>[self.mutYDic[maxCol] floatValue]) {
maxCol=col;
}
}
return maxCol;
}
//比较最大的Y值
-(NSString*)minCol{
NSString *minCol=@"0";
for (int i=0; i<self.countLine; i++) {
NSString *col=[NSString stringWithFormat:@"%d",i];
if ([self.mutYDic[col] floatValue]<[self.mutYDic[minCol] floatValue]) {
minCol=col;
}
}
return minCol;
}
//系统会调用这个方法,接收布局属性数组,用于每一个cell的布局
//系统的布局数组我们并不需要,我们需要自己重新计算每一个cell的布局属性,。返回给collectionView使用
//返回数组
-(NSArray<UICollectionViewLayoutAttributes*>*)layoutAttributesForElementsInRect:(CGRect)rect{
[super layoutAttributesForElementsInRect:rect];
return self.attArr;
}
@end
重点是坐标的计算
//确定cell
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
XYImgCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"img" forIndexPath:indexPath];
//在拖拽的时候改变
NSInteger index=(indexPath.item-1+ctn+self.currentIndex)%ctn;
// NSInteger index=(self.currentIndex-1)%ctn;
// NSLog(@"cell-%ld",index);
cell.img=self.arrImg[index];
cell.indexPath=indexPath;
return cell;
}
//每次拖拽的时候都回到索引为1的地方,但是改变显示的图片
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
//获得偏移量
NSInteger offset=self.collectionView.contentOffset.x/self.collectionView.bounds.size.width-1;
self.currentIndex=(offset+ctn+self.currentIndex)%ctn;
// NSLog(@"滚动-%ld",self.currentIndex);
//实现单线程操作,避免快速拖拽的时候出现混乱
dispatch_async(dispatch_get_main_queue(), ^{
//让第一次显示的索引在为1的位置,但显示第0张图片
NSIndexPath *path=[NSIndexPath indexPathForItem:1 inSection:0];
[self.collectionView scrollToItemAtIndexPath:path atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
});
}