iOS UICollectionView实现标签选择器
近来,在项目中需要实现一个类似兴趣标签的选择器。由于标签的文字长度不定,所以标签的显示长度就不定。为了实现效果,就使用了UICollectionView来实现了每行的标签数量不定、cell的宽度自适应的效果。先在此分享出来:
1、自适应UICollectionViewCell
这里只是在自适应UICollectionViewCell上放一个和UICollectionViewCell保持一样大小的按钮,当选中和取消选中时改变按钮的文字颜色和边框颜色:
#pragmamark---标签cell @implementationYLTagsCollectionViewCell -(instancetype)initWithFrame:(CGRect)frame { if(self=[superinitWithFrame:frame]){ self.backgroundColor=[UIColorclearColor]; _btn=[UIButtonbuttonWithType:UIButtonTypeCustom]; //此处可以根据需要自己使用自动布局代码实现 _btn.frame=CGRectMake(0,0,frame.size.width,frame.size.height); _btn.backgroundColor=[UIColorwhiteColor]; _btn.titleLabel.font=[UIFontsystemFontOfSize:14]; _btn.layer.borderWidth=1.f; _btn.layer.cornerRadius=frame.size.height/2.0; _btn.layer.masksToBounds=YES; [_btnsetTitleColor:HEXCOLOR(0x666666)forState:UIControlStateNormal]; _btn.layer.borderColor=HEXCOLOR(0xdddddd).CGColor; _btn.userInteractionEnabled=NO; [self.contentViewaddSubview:_btn]; } returnself; } -(void)layoutSubviews { [superlayoutSubviews]; _btn.frame=CGRectMake(0,0,self.contentView.frame.size.width,self.contentView.frame.size.height); } -(void)setSelected:(BOOL)selected { [supersetSelected:selected]; _btn.layer.borderColor=selected?HEXCOLOR(0xffb400).CGColor:HEXCOLOR(0xdddddd).CGColor; [_btnsetTitleColor:selected?HEXCOLOR(0xffb400):HEXCOLOR(0x666666)forState:UIControlStateNormal]; } -(void)setHighlighted:(BOOL)highlighted { [supersetHighlighted:highlighted]; _btn.layer.borderColor=highlighted?HEXCOLOR(0xffb400).CGColor:HEXCOLOR(0xdddddd).CGColor; [_btnsetTitleColor:highlighted?HEXCOLOR(0xffb400):HEXCOLOR(0x666666)forState:UIControlStateNormal]; } @end
2、UICollectionViewFlowLayout子类--YLWaterFlowLayout的实现
.h头文件
#import@classYLWaterFlowLayout; @protocolYLWaterFlowLayoutDelegate /**通过代理获得每个cell的宽度*/ -(CGFloat)waterFlowLayout:(YLWaterFlowLayout*)layout widthAtIndexPath:(NSIndexPath*)indexPath; @end @interfaceYLWaterFlowLayout:UICollectionViewFlowLayout @property(nonatomic,assign)id delegate; @property(nonatomic,assign)CGFloatrowHeight;///<固定行高 @end
.m文件
#import"YLWaterFlowLayout.h" @interfaceYLWaterFlowLayout() @property(nonatomic,strong)NSMutableArray*originxArray; @property(nonatomic,strong)NSMutableArray*originyArray; @end @implementationYLWaterFlowLayout #pragmamark-初始化属性 -(instancetype)init{ self=[superinit]; if(self){ self.minimumInteritemSpacing=5;//同一行不同cell间距 self.minimumLineSpacing=5;//行间距 self.sectionInset=UIEdgeInsetsMake(10,10,10,10); self.scrollDirection=UICollectionViewScrollDirectionVertical; _originxArray=[NSMutableArrayarray]; _originyArray=[NSMutableArrayarray]; } returnself; } #pragmamark-重写父类的方法,实现瀑布流布局 #pragmamark-当尺寸有所变化时,重新刷新 -(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ returnYES; } -(void)prepareLayout{ [superprepareLayout]; } #pragmamark-处理所有的Item的layoutAttributes -(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect { NSArray*array=[superlayoutAttributesForElementsInRect:rect]; NSMutableArray*mutArray=[NSMutableArrayarrayWithCapacity:array.count]; for(UICollectionViewLayoutAttributes*attrsinarray){ UICollectionViewLayoutAttributes*theAttrs=[selflayoutAttributesForItemAtIndexPath:attrs.indexPath]; [mutArrayaddObject:theAttrs]; } returnmutArray; } #pragmamark-处理单个的Item的layoutAttributes -(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath { CGFloatx=self.sectionInset.left; CGFloaty=self.sectionInset.top; //判断获得前一个cell的x和y NSIntegerpreRow=indexPath.row-1; if(preRow>=0){ if(_originyArray.count>preRow){ x=[_originxArray[preRow]floatValue]; y=[_originyArray[preRow]floatValue]; } NSIndexPath*preIndexPath=[NSIndexPathindexPathForItem:preRowinSection:indexPath.section]; CGFloatpreWidth=[self.delegatewaterFlowLayout:selfwidthAtIndexPath:preIndexPath]; x+=preWidth+self.minimumInteritemSpacing; } CGFloatcurrentWidth=[self.delegatewaterFlowLayout:selfwidthAtIndexPath:indexPath]; //保证一个cell不超过最大宽度 currentWidth=MIN(currentWidth,self.collectionView.frame.size.width-self.sectionInset.left-self.sectionInset.right); if(x+currentWidth>self.collectionView.frame.size.width-self.sectionInset.right){ //超出范围,换行 x=self.sectionInset.left; y+=_rowHeight+self.minimumLineSpacing; } //创建属性 UICollectionViewLayoutAttributes*attrs=[UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath]; attrs.frame=CGRectMake(x,y,currentWidth,_rowHeight); _originxArray[indexPath.row]=@(x); _originyArray[indexPath.row]=@(y); returnattrs; } #pragmamark-CollectionView的滚动范围 -(CGSize)collectionViewContentSize { CGFloatwidth=self.collectionView.frame.size.width; __blockCGFloatmaxY=0; [_originyArrayenumerateObjectsUsingBlock:^(NSNumber*number,NSUIntegeridx,BOOL*_Nonnullstop){ if([numberfloatValue]>maxY){ maxY=[numberfloatValue]; } }]; returnCGSizeMake(width,maxY+_rowHeight+self.sectionInset.bottom); } @end
实现思路:在YLWaterFlowLayout中使用originxArray和originyArray两个个数组记录了每一个自定义YLTagsCollectionViewCell的位置x和y。
在-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath方法中通获得与当前YLTagsCollectionViewCell临近的“上一个YLTagsCollectionViewCell”的位置和尺寸信息,将上一个cell的x加上上一个cell的width来得到当前cell的x。同时还要判断当前cell的x+width是否会超越出屏幕右边缘,如果超出,则表明需要换行显示了,这时候就要修改y的值了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。