先上图。
对该视图的封装
#import <UIKit/UIKit.h>
typedef void(^TagListViewOnTagClick)(NSUInteger index, NSString *tag);
/// 标签样式风格
typedef NS_ENUM(NSInteger, TagListViewStyle) {
/// 标准大小
TagListViewStyleStd,
/// 大的
TagListViewStyleBig,
};
@interface searchTagListView : UIView
+ (CGFloat)heightWithTags:(NSArray<NSString *> *)tags style:(TagListViewStyle)style;
/// 标签整体内容上间隔。默认0
@property (nonatomic, assign) CGFloat contentTopMargin;
/// 标签数据
@property (nonatomic, copy) NSArray<NSString *> *tags;
- (instancetype)initWithStyle:(TagListViewStyle)style;
/// 用户点击了某个标签
- (void)onTagClick:(TagListViewOnTagClick)block;
@end
#import "searchTagListView.h"
@interface searchTagListView ()
@property (nonatomic, strong) NSMutableArray<UIButton *> *tagButtonList;
@property (nonatomic, assign) TagListViewStyle style;
@property (nonatomic, copy) TagListViewOnTagClick onTagClickBlock;
@end
static CGFloat const kContentLeftRightMargin = 10;
static CGFloat const kTagHeight_std = 25;
static CGFloat const kTagHeight_big = 30;
static CGFloat const kTagSpacing = 15;
static CGFloat const kButtonTitleLeftRightMargin_std = 10;
static CGFloat const kButtonTitleLeftRightMargin_big = 8;
#define kTagFont_std [UIFont fanZhengLanTingXHFontWithSize:11]
#define kTagFont_big [UIFont fanZhengLanTingXHFontWithSize:14]
@implementation searchTagListView
/**
* 计算标签视图需要的高度
*
* @param tags 标签列表
* @param tagItemHandle 处理回调,通知外面这个Tag的显示信息
*
* @return Tags在UI上的高度。
*/
+ (CGFloat)_heightWithTags:(NSArray<NSString *> *)tags style:(TagListViewStyle)style tagItemHandle:(void(^)(NSUInteger index, NSString *tagName, CGSize tagSize, BOOL needWrap))tagItemHandle {
__block CGFloat tagsHeight = 0;
if (tags && (tags.count > 0)) {
UIFont *font = (style == TagListViewStyleStd ? kTagFont_std : kTagFont_big);
CGFloat titleLeftRightMargin = (style == TagListViewStyleStd ? kButtonTitleLeftRightMargin_std : kButtonTitleLeftRightMargin_big);
CGFloat tagHeight = (style == TagListViewStyleStd ? kTagHeight_std : kTagHeight_big);
tagsHeight += tagHeight;
CGFloat tagsContentWdith = SCREEN_WIDTH - kContentLeftRightMargin * 2;
__block CGFloat currentRowWidth = tagsContentWdith;
[tags enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
CGFloat tagWidth = [obj boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : font} context:nil].size.width + titleLeftRightMargin * 2 + 3;
BOOL needWrap = NO;
if (tagWidth > currentRowWidth && currentRowWidth != tagsContentWdith) {
// 换行
tagsHeight += kTagSpacing + tagHeight;
currentRowWidth = tagsContentWdith;
needWrap = YES;
}
GCBlockInvoke(tagItemHandle, idx, obj, CGSizeMake(MIN(tagWidth, tagsContentWdith), tagHeight), needWrap);
currentRowWidth -= (tagWidth + kTagSpacing);
}];
}
return tagsHeight;
}
+ (CGFloat)heightWithTags:(NSArray<NSString *> *)tags style:(TagListViewStyle)style {
return [self _heightWithTags:tags style:style tagItemHandle:nil];
}
- (instancetype)init {
if (self = [super init]) {
self.contentTopMargin = 0;
self.tagButtonList = [NSMutableArray array];
self.style = TagListViewStyleStd;
}
return self;
}
- (instancetype)initWithStyle:(TagListViewStyle)style {
if (self = [super init]) {
self.contentTopMargin = 0;
self.tagButtonList = [NSMutableArray array];
self.style = style;
}
return self;
}
#pragma mark - public methods
- (void)setTags:(NSArray<NSString *> *)tags {
_tags = [tags copy];
[self _reloadButtonList];
}
- (void)onTagClick:(TagListViewOnTagClick)block {
self.onTagClickBlock = block;
}
#pragma mark - private methods
- (UIButton *)_createButtonWithTagName:(NSString *)tagName {
UIButton *button = [[UIButton alloc] init];
button.titleLabel.font = (self.style == TagListViewStyleStd ? kTagFont_std : kTagFont_big);
button.backgroundColor = k_COLOR_E7E7E7;
CGFloat titleLeftRightMargin = (self.style == TagListViewStyleStd ? kButtonTitleLeftRightMargin_std : kButtonTitleLeftRightMargin_big);
button.contentEdgeInsets = UIEdgeInsetsMake(0, titleLeftRightMargin, 0, titleLeftRightMargin);
button.layer.cornerRadius = (self.style == TagListViewStyleStd ? kTagHeight_std : kTagHeight_big) * 0.5;
button.layer.borderWidth = 0;
[button setTitle:tagName forState:UIControlStateNormal];
[button setTitleColor:k_COLOR_949494 forState:UIControlStateNormal];
_weak(self);
[button addControlEvents:UIControlEventTouchUpInside action:^(UIControl *control, NSSet *touches) {
_strong_check(self);
GCBlockInvoke(self.onTagClickBlock, control.tag, [(UIButton *)control titleForState:UIControlStateNormal]);
}];
return button;
}
- (void)_reloadButtonList {
[self.tagButtonList enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj removeFromSuperview];
}];
[self.tagButtonList removeAllObjects];
__block UIView *prevView = nil;
[searchTagListView _heightWithTags:self.tags style:self.style tagItemHandle:^(NSUInteger index, NSString *tagName, CGSize tagSize, BOOL needWrap) {
UIButton *btn = [self _createButtonWithTagName:tagName];
[self addSubview:btn];
[self.tagButtonList addObject:btn];
UIButton *button = self.tagButtonList[index];
[button mas_remakeConstraints:^(MASConstraintMaker *make) {
if (prevView == nil) {
make.left.equalTo(self).offset(kContentLeftRightMargin);
make.top.equalTo(self).offset(self.contentTopMargin);
}
else if (needWrap) {
make.left.equalTo(self).offset(kContentLeftRightMargin);
make.top.equalTo(prevView.mas_bottom).offset(kTagSpacing);
}
else {
make.left.equalTo(prevView.mas_right).offset(kTagSpacing);
make.top.equalTo(prevView);
}
make.size.mas_equalTo(tagSize);
}];
prevView = button;
}];
}
@end
*使用方法
CGFloat height=[searchTagListView heightWithTags:_tagListView.tags style:TagListViewStyleStd];
[self.hotTagLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.searchView.mas_bottom).offset(-12);
make.left.equalTo(self.view);
make.width.equalTo(@75);
make.height.equalTo(@40);
}];
-(searchTagListView *)tagListView{
if (!_tagListView) {
_weak(self);
_tagListView=[[searchTagListView alloc] initWithStyle:TagListViewStyleStd];
_tagListView.backgroundColor=self.view.backgroundColor;
[_tagListView onTagClick:^(NSUInteger index, NSString *tag) {
_strong_check(self);
[self.searchTextField resignFirstResponder];
self.keyword=tag;
[self _loadDataWithIsLatest:YES];
}];
}
return _tagListView;
}
使用方法截自项目,封装的类中含有项目中定义的宏替换掉就可以了
最后附上封装类中出现的宏
#if defined(__LP64__) && __LP64__
# define CGFLOAT_TYPE double
# define CGFLOAT_IS_DOUBLE 1
# define CGFLOAT_MIN DBL_MIN
# define CGFLOAT_MAX DBL_MAX
#else
# define CGFLOAT_TYPE float
# define CGFLOAT_IS_DOUBLE 0
# define CGFLOAT_MIN FLT_MIN
# define CGFLOAT_MAX FLT_MAX
#endif
#define GCBlockInvoke(block, ...) \
do { \
if (block) { \
block(__VA_ARGS__); \
} \
} while(0)
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
#define _weak(x) __weak typeof(x) weak##x = x
#define _strong(x) typeof(weak##x) x = weak##x
#define _strong_check(x, ...) typeof(weak##x) x = weak##x; if (!weak##x) return __VA_ARGS__;
#define RGB(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define k_COLOR_E7E7E7 RGB(221, 225, 224)
#define k_COLOR_949494 RGB(142, 151, 146)