当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS UICollectionView实现标签选择器

iOS UICollectionView实现标签选择器

2020年05月14日  | 移动技术网IT编程  | 我要评论

推土螃蟹,治疗兔子,船长克星弗洛格

近来,在项目中需要实现一个类似兴趣标签的选择器。由于标签的文字长度不定,所以标签的显示长度就不定。为了实现效果,就使用了uicollectionview来实现了每行的标签数量不定、cell的宽度自适应的效果。先在此分享出来:

1、自适应uicollectionviewcell

这里只是在自适应uicollectionviewcell上放一个和uicollectionviewcell保持一样大小的按钮,当选中和取消选中时改变按钮的文字颜色和边框颜色:

#pragma mark---标签cell
@implementation yltagscollectionviewcell
-(instancetype)initwithframe:(cgrect)frame
{
 if(self = [super initwithframe:frame]){
  self.backgroundcolor = [uicolor clearcolor];
  _btn = [uibutton buttonwithtype:uibuttontypecustom];
  //此处可以根据需要自己使用自动布局代码实现
  _btn.frame = cgrectmake(0, 0, frame.size.width, frame.size.height);
  _btn.backgroundcolor = [uicolor whitecolor];
  _btn.titlelabel.font = [uifont systemfontofsize:14];
  _btn.layer.borderwidth = 1.f;
  _btn.layer.cornerradius = frame.size.height/2.0;
  _btn.layer.maskstobounds = yes;
  [_btn settitlecolor:hexcolor(0x666666) forstate:uicontrolstatenormal];
  _btn.layer.bordercolor = hexcolor(0xdddddd).cgcolor;
  _btn.userinteractionenabled = no;
  [self.contentview addsubview:_btn];
 }
 return self;
}
 
-(void)layoutsubviews
{
 [super layoutsubviews];
 _btn.frame = cgrectmake(0, 0, self.contentview.frame.size.width, self.contentview.frame.size.height);
}
 
-(void)setselected:(bool)selected
{
 [super setselected:selected];
 _btn.layer.bordercolor = selected?hexcolor(0xffb400).cgcolor:hexcolor(0xdddddd).cgcolor;
 [_btn settitlecolor:selected?hexcolor(0xffb400):hexcolor(0x666666) forstate:uicontrolstatenormal];
}
 
-(void)sethighlighted:(bool)highlighted
{
 [super sethighlighted:highlighted];
 _btn.layer.bordercolor = highlighted?hexcolor(0xffb400).cgcolor:hexcolor(0xdddddd).cgcolor;
 [_btn settitlecolor:highlighted?hexcolor(0xffb400):hexcolor(0x666666) forstate:uicontrolstatenormal];
}
 
@end

2、uicollectionviewflowlayout子类--ylwaterflowlayout的实现

.h头文件

#import <uikit/uikit.h>
 
@class ylwaterflowlayout;
@protocol ylwaterflowlayoutdelegate <nsobject>
/**通过代理获得每个cell的宽度*/
- (cgfloat)waterflowlayout:(ylwaterflowlayout *)layout 
widthatindexpath:(nsindexpath *)indexpath;
 
@end
 
@interface ylwaterflowlayout : uicollectionviewflowlayout
@property (nonatomic,assign) id<ylwaterflowlayoutdelegate> delegate;
@property(nonatomic,assign)cgfloat rowheight;///< 固定行高
 
@end

.m文件

#import "ylwaterflowlayout.h"
 
@interface ylwaterflowlayout()
@property(nonatomic,strong)nsmutablearray *originxarray;
@property(nonatomic,strong)nsmutablearray *originyarray;
@end
 
@implementation ylwaterflowlayout
#pragma mark - 初始化属性
- (instancetype)init {
 self = [super init];
 if (self) {
  self.minimuminteritemspacing = 5;//同一行不同cell间距
  self.minimumlinespacing = 5;//行间距
  self.sectioninset = uiedgeinsetsmake(10, 10, 10, 10);
  self.scrolldirection = uicollectionviewscrolldirectionvertical;
  _originxarray = [nsmutablearray array];
  _originyarray = [nsmutablearray array];
 }
 return self;
}
 
#pragma mark - 重写父类的方法,实现瀑布流布局
#pragma mark - 当尺寸有所变化时,重新刷新
- (bool)shouldinvalidatelayoutforboundschange:(cgrect)newbounds {
 return yes;
}
 
- (void)preparelayout {
 [super preparelayout];
}
 
#pragma mark - 处理所有的item的layoutattributes
- (nsarray *)layoutattributesforelementsinrect:(cgrect)rect
{
 nsarray *array = [super layoutattributesforelementsinrect:rect];
 nsmutablearray *mutarray = [nsmutablearray arraywithcapacity:array.count];
 for(uicollectionviewlayoutattributes *attrs in array){
  uicollectionviewlayoutattributes *theattrs = [self layoutattributesforitematindexpath:attrs.indexpath];
  [mutarray addobject:theattrs];
 }
 return mutarray;
}
 
#pragma mark - 处理单个的item的layoutattributes
- (uicollectionviewlayoutattributes *)layoutattributesforitematindexpath:(nsindexpath *)indexpath
{
 cgfloat x = self.sectioninset.left;
 cgfloat y = self.sectioninset.top;
 //判断获得前一个cell的x和y
 nsinteger prerow = indexpath.row - 1;
 if(prerow >= 0){
  if(_originyarray.count > prerow){
   x = [_originxarray[prerow]floatvalue];
   y = [_originyarray[prerow]floatvalue];
  }
  nsindexpath *preindexpath = [nsindexpath indexpathforitem:prerow insection:indexpath.section];
  cgfloat prewidth = [self.delegate waterflowlayout:self widthatindexpath:preindexpath];
  x += prewidth + self.minimuminteritemspacing;
 }
 
 cgfloat currentwidth = [self.delegate waterflowlayout:self widthatindexpath: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 = [uicollectionviewlayoutattributes layoutattributesforcellwithindexpath:indexpath];
 attrs.frame = cgrectmake(x, y, currentwidth, _rowheight);
 _originxarray[indexpath.row] = @(x);
 _originyarray[indexpath.row] = @(y);
 return attrs;
}
 
#pragma mark - collectionview的滚动范围
- (cgsize)collectionviewcontentsize
{
 cgfloat width = self.collectionview.frame.size.width;
 
 __block cgfloat maxy = 0;
 [_originyarray enumerateobjectsusingblock:^(nsnumber *number, nsuinteger idx, bool * _nonnull stop) {
  if ([number floatvalue] > maxy) {
   maxy = [number floatvalue];
  }
 }];
 
 return cgsizemake(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的值了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网