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的值了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。