最近项目里面用到了流式标签(刚开始我还不知道这种视图叫做流式标签,还是旁边的安卓小伙伴告诉我的),今天就来总结一下我在网上照着别人写的流式标签视图是怎么实现的。
第一种方式:for循环创建多个视图添加到UIScrollView中。
h文件
#import <UIKit/UIKit.h>
/**
标签视图内部子元素,用来显示一个一个的标签
*/
@interface LQTagView : UIView
/**
设置标签元素内容
@param data 字典类型 title表示标签标题,logo表示标签logo图片
*/
- (void)setupWithData:(NSDictionary *)data;
@end
@class LQFlowTagListView;
@protocol LQFlowTagListViewDelegate <NSObject>
/**
代理方法,实现子标签的点击事件
@param listView 当前标签列表视图
@param index 点击的第几个标签
@param data 该标签所带的内容(title, logo)
*/
- (void)tagListView:(LQFlowTagListView *)listView didSelectTagViewItemAtIndex:(NSInteger)index selectItemData:(NSDictionary *)data;
@end
/**
流式标签列表视图
*/
@interface LQFlowTagListView : UIScrollView
@property (nonatomic, weak) id <LQFlowTagListViewDelegate> tagDelegate;
/**
给整个标签列表视图设置元数据
@param data 数组类型,数组的count代表子标签的个数
*/
- (void)setupSubViewsWithData:(NSArray *)data;
@end
m文件
#import "LQFlowTagListView.h"
@interface LQTagView ()
@property (nonatomic, strong) UIImageView *logoImageV;
@property (nonatomic, strong) UILabel *titleLB;
@end
@implementation LQTagView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor whiteColor];
[self addSubview:self.logoImageV];
[self addSubview:self.titleLB];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
//logo,title在标签内部的位置
self.logoImageV.frame = CGRectMake(5, 5, 30, 20);
self.titleLB.frame = CGRectMake(45, 5, self.frame.size.width - 55, 20);
}
#pragma mark -
#pragma mark - UI
- (void)setupWithData:(NSDictionary *)data {
self.logoImageV.image = [UIImage imageNamed:@"logo"];
self.titleLB.text = [data objectForKey:@"title"];
//根据title内容计算titleLB的长度,确定标签视图的宽
UIFont *font = self.titleLB.font;
CGSize size = [[data objectForKey:@"title"] sizeWithAttributes:@{NSFontAttributeName: font}];
CGRect frame = self.frame;
frame.size = CGSizeMake(size.width + 55, 30);
self.frame = frame;
}
#pragma mark -
#pragma mark - Lazy init
- (UILabel *)titleLB {
if (!_titleLB) {
_titleLB = [[UILabel alloc] init];
_titleLB.textColor = [UIColor grayColor];
_titleLB.font = [UIFont systemFontOfSize:14.f];
}
return _titleLB;
}
- (UIImageView *)logoImageV {
if (!_logoImageV) {
_logoImageV = [[UIImageView alloc] init];
_logoImageV.backgroundColor = [UIColor redColor];
}
return _logoImageV;
}
@end
@interface LQFlowTagListView ()
//用来存放所有子标签的动态数组,后面从该数组中循环取出LQTagView计算frame
@property (nonatomic, strong) NSMutableArray *tags;
//用来保存标签列表元数据
@property (nonatomic, strong) NSArray *data;
@end
@implementation LQFlowTagListView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.bounces = NO;
self.pagingEnabled = YES;
}
return self;
}
#pragma mark -
#pragma mark - UI
- (void)setupSubViewsWithData:(NSArray *)data {
self.data = data;
//移除所有子视图
[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
//清空保存子视图数组
[self.tags removeAllObjects];
//for循环创建子标签,添加到标签列表视图中
for (NSInteger i = 0; i < data.count; i++) {
//不用设置frame,会根据设置的内容在LQTagView内部自动计算宽高,后面会用循环计算x,y(origin)
LQTagView *tagV = [[LQTagView alloc] initWithFrame:CGRectZero];
[tagV setupWithData:data[i]];
[self addSubview:tagV];
[self.tags addObject:tagV];
tagV.tag = i;
//给子标签添加点击事件
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectTagClick:)];
[tagV addGestureRecognizer:tapGesture];
}
//计算所有子标签的x,y(origin),宽高在视图内部计算
[self setupAllSubViews];
}
- (void)layoutSubviews {
[super layoutSubviews];
[self setupAllSubViews];
}
- (void)setupAllSubViews {
//标签列表内部子标签之间的左右,上下间距
CGFloat marginX = 20;
CGFloat marginY = 20;
//子标签的frame的坐标x,y(origin)
__block CGFloat x = 0;
__block CGFloat y = 10;
//循环self.tags数组,计算所有子标签x,y(origin)
[self.tags enumerateObjectsUsingBlock:^(LQTagView *obj, NSUInteger idx, BOOL * _Nonnull stop) {
CGFloat height = CGRectGetHeight(obj.frame);
if (idx == 0) {
//第一个子标签(x = marginY, y = 10)
x = marginX;
} else {
//后面的子标签,x = 前一个子标签的x + 宽 + 间距(marginX)
x = CGRectGetMaxX([self.tags[idx - 1] frame]) + marginX;
//如果x + 该子标签的宽 + 间距 > 标签列表的宽 就换行显示
if (x + CGRectGetWidth(obj.frame) + marginX > CGRectGetWidth(self.frame)) {
x = marginX;
y += height;
y += marginY;
}
}
//设置子标签的x,y(origin)
CGRect frame = obj.frame;
frame.origin = CGPointMake(x, y);
obj.frame = frame;
}];
//如果只有一行,居中显示
if (y == 10) {
[self.tags enumerateObjectsUsingBlock:^(LQTagView *obj, NSUInteger idx, BOOL * _Nonnull stop) {
CGFloat height = CGRectGetHeight(obj.frame);
y = CGRectGetHeight(self.frame) / 2 - height / 2.0;
if (idx == 0) {
x = marginX;
} else {
x = CGRectGetMaxX([self.tags[idx - 1] frame]) + marginX;
}
CGRect frame = obj.frame;
frame.origin = CGPointMake(x, y);
obj.frame = frame;
}];
}
//计算标签列表视图的contentSize
CGFloat contentHeight = CGRectGetMaxY([self.tags.lastObject frame]) + 10;
if (contentHeight < CGRectGetHeight(self.frame)) {
contentHeight = 0;
}
self.contentSize = CGSizeMake(0, contentHeight);
}
#pragma mark -
#pragma mark - Actions
//给每个子标签视图添加的点击事件(实现代理)
- (void)selectTagClick:(UITapGestureRecognizer *)tap {
LQTagView *tagV = (LQTagView *)tap.view;
if ([self.tagDelegate respondsToSelector:@selector(tagListView:didSelectTagViewItemAtIndex:selectItemData:)]) {
[self.tagDelegate tagListView:self didSelectTagViewItemAtIndex:tagV.tag selectItemData:[self.data objectAtIndex:tagV.tag]];
}
}
#pragma mark -
#pragma mark - Lazy init
- (NSMutableArray *)tags {
if (!_tags) {
_tags = [NSMutableArray array];
}
return _tags;
}
@end
使用方法
//tag标签
LQFlowTagListView *tagListV = [[LQFlowTagListView alloc]initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 0)];
tagListV.tagDelegate = self;
[tagListV setupSubViewsWithData:@[@{@"title":@"观途"},@{@"title":@"哈朗逸"},@{@"title":@"途昂"},@{@"title":@"大众polo"},@{@"title":@"哈宝来"},@{@"title":@"捷达"},@{@"title":@"思域"},@{@"title":@"保时捷"},@{@"title":@"一汽大众"},]];
[self.view addSubview:tagListV];
CGRect rect = tagListV.frame;
rect.size.height = tagListV.contentSize.height;
tagListV.frame = rect;
转载:流式标签
第二种方式:直接使用UICollectionView显示,处理好UICollectionViewFlowLayout
。
待续~
慢慢来,一步一个巴掌印~~~
网友评论