虚位以待(AD)
虚位以待(AD)
首页 > 软件编程 > IOS编程/Objective-C > iOS 主流搜索界面下的Tag标签布局框架(SKTagView)

iOS 主流搜索界面下的Tag标签布局框架(SKTagView)
类别:IOS编程/Objective-C   作者:码皇   来源:Deft_MKJing的博客     点击:

每个App的搜索界面下边都会有热门搜索,历史搜索之类的标签,这里介绍个框架,既可以非常容易实现标签类的不规则流式布局,也可以实现固定宽度和高度的布局,也支持Autolayout,使用起来也是非常舒服。SKTagView原框架下只有根据文字宽度不固定的的模式

每个App的搜索界面下边都会有热门搜索,历史搜索之类的标签,这里介绍个框架,既可以非常容易实现标签类的不规则流式布局,也可以实现固定宽度和高度的布局,也支持Autolayout,使用起来也是非常舒服。SKTagView原框架下只有根据文字宽度不固定的的模式,那么如果需求有固定宽高模式的,老规矩,只能改源码了.

请看图:

传统模式:

 

TableView cell模式的不规则模式和固定宽高模式:

 

电影放完了,开始简单介绍下

 

这里有两个能用到的地方(截图来自淘宝)

 

OK,根据以上两个用途,写了两个简单的Demo,无需再繁琐的计算了,直接导入

SKTagView来进行布局,非常简单

Demo地址:https://github.com/DeftMKJ/SKTag

 

 

 

Demo1

首先:

创建一个UISearchBar来进行模拟搜索

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib. UIView *titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 375, 44)];
    titleView.backgroundColor = [UIColor clearColor];
    self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 360, 44)];
    self.searchBar.delegate = self;
    self.searchBar.placeholder = @"请输入要搜索的文字";
    // self.searchBar.showsCancelButton = YES;
    // 键盘确认按钮的名字 self.searchBar.returnKeyType = UIReturnKeyNext;
    // 把默认灰色背景浮层给去掉 self.searchBar.backgroundColor = [UIColor clearColor];
    self.searchBar.backgroundImage = [UIImage new];
    UITextField *searBarTextField = [self.searchBar valueForKey:@"_searchField"];
    if (searBarTextField) {
    [searBarTextField setBackgroundColor:[UIColor colorWithRed:243/255.0 green:243/255.0 blue:243/255.0 alpha:1]];
    searBarTextField.borderStyle = UITextBorderStyleRoundedRect;
    searBarTextField.layer.cornerRadius = 5.0f;
    }
    else {
    // 通过颜色画一个Image出来 UIImage *image = [UIImage imageWithColor:[UIColor colorWithRed:243/255.0 green:243/255.0 blue:243/255.0 alpha:1] forSize:CGSizeMake(28, 28)];
    [self.searchBar setSearchFieldBackgroundImage:image forState:UIControlStateNormal];
    }
    [titleView addSubview:self.searchBar];
    self.navigationItem.titleView = titleView;
    [self.searchBar becomeFirstResponder];
    [self configTagView];
    }

 

来看看效果哈

 

 

但是你们有没有觉得他右边的Cancel一点都协调么,要改了它,但是这东西

系统又没有给属性接口让你改......

 

那么试着咱们把SearchBar下面的Subviews统统打印出来看一下

咦???这个数组里面只有个UIView么,不科学啊,要不再拨开一层看看

NICE啊,这波操作可以啊,找到了,藏那么里面,既然找到了,就在这个代理方法里面进行修改

 

    - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
    // (lldb) po self.searchBar.subviews[0].subviews// <__NSArrayM 0x7ffba1e08330>(// >,// >,// >// ) // // (lldb) po self.searchBar.subviews// <__NSArrayM 0x7ffba1e77280>(// >// ) searchBar.showsCancelButton = YES;
    for(UIView *view in [[[searchBar subviews] objectAtIndex:0] subviews]) {
    if([view isKindOfClass:[NSClassFromString(@"UINavigationButton") class]]) {
    UIButton * cancel =(UIButton *)view;
    [cancel setTitle:@"搜索" forState:UIControlStateNormal];
    cancel.titleLabel.font = [UIFont systemFontOfSize:14];
    cancel.tintColor = [UIColor redColor];
    }
    }
    }

修改完后的效果(Mac这截图效果也是醉了

 

然后

我们来创建SKTagView,各种属性已经加上注释

 

    // 配置- (void)configTagView{
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(10, 90, 100, 30)];
    self.label.textColor = [UIColor blackColor];
    self.label.font = [UIFont systemFontOfSize:13];
    self.label.text = @"历史搜索";
    [self.view addSubview:self.label];
    // 先移除掉所有 [self.tagView removeAllTags];
    // 初始化 self.tagView = [[SKTagView alloc] init];
    // 整个tagView对应其SuperView的上左下右距离 self.tagView.padding = UIEdgeInsetsMake(10, 10, 10, 10);
    // 上下行之间的距离 self.tagView.lineSpacing = 10;
    // item之间的距离 self.tagView.interitemSpacing = 20;
    // 最大宽度 self.tagView.preferredMaxLayoutWidth = 375;
    // @property (assign, nonatomic) CGFloat regularWidth;
    //!< 固定宽度// @property (nonatomic,assign ) CGFloat regularHeight;
    //!< 固定高度 // 原作者没有能加固定宽度的,自己修改源码加上了固定宽度和高度,默认是0,就是标签式布局,如果实现了,那么就是固定宽度高度// self.tagView.regularWidth = 100;
    // self.tagView.regularHeight = 30;
    // 开始加载 [self.dataSource enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    // 初始化标签 SKTag *tag = [[SKTag alloc] initWithText:self.dataSource[idx]];
    // 标签相对于自己容器的上左下右的距离 tag.padding = UIEdgeInsetsMake(3, 15, 3, 15);
    // 弧度 tag.cornerRadius = 3.0f;
    // 字体 tag.font = [UIFont boldSystemFontOfSize:12];
    // 边框宽度 tag.borderWidth = 0;
    // 背景 tag.bgColor = [UIColor colorWithRed:244/255.0 green:244/255.0 blue:244/255.0 alpha:1];
    // 边框颜色 tag.borderColor = [UIColor colorWithRed:191/255.0 green:191/255.0 blue:191/255.0 alpha:1];
    // 字体颜色 tag.textColor = [UIColor colorWithRed:53/255.0 green:53/255.0 blue:53/255.0 alpha:1];
    // 是否可点击 tag.enable = YES;
    // 加入到tagView [self.tagView addTag:tag];
    }
    ];
    // 点击事件回调 self.tagView.didTapTagAtIndex = ^(NSUInteger idx){
    NSLog(@"点击了第%ld个",idx);
    }
    ;
    // 获取刚才加入所有tag之后的内在高度 CGFloat tagHeight = self.tagView.intrinsicContentSize.height;
    NSLog(@"高度%lf",tagHeight);
    // 根据已经得到的内在高度给SKTagView创建frame self.tagView.frame = CGRectMake(0, 120, 375, tagHeight);
    [self.tagView layoutSubviews];
    [self.view addSubview:self.tagView];
    }

最后

 

在UISearchBar的代理方法里面实现搜索的时候隐藏,不搜索的时候显示

 

    - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
    NSLog(@"%@",searchText);
    if (searchText.length == 0) {
    // 没有文字了 self.label.hidden = NO;
    self.tagView.hidden = NO;
    }
    else {
    self.label.hidden = YES;
    self.tagView.hidden = YES;
    }
    }


 

三步做完,一个简单的Demo就做完了,简单到爆......

下面咱们来看看如何让他在TableViewCell里面实现高度自适应的

(需要用到的库UITableView+FDTemplateLayoutCell--->传送门)

Demo2

首先

用Xib做一个SKTagView的Cell

 

然后

不需要给SKTagView指定Frame了,约束已经做好,只要实现下面的代码就好了

 

    - (void)configCell:(MKJTagViewTableViewCell *)cell indexpath:(NSIndexPath *)indexpath{
    [cell.tagView removeAllTags];
    cell.tagView.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width;
    cell.tagView.padding = UIEdgeInsetsMake(20, 20, 20, 20);
    cell.tagView.lineSpacing = 20;
    cell.tagView.interitemSpacing = 30;
    cell.tagView.singleLine = NO;
    // 给出两个字段,如果给的是0,那么就是变化的,如果给的不是0,那么就是固定的 cell.tagView.regularWidth = 80;
    cell.tagView.regularHeight = 30;
    NSArray *arr = [self.dataSource[indexpath.row] valueForKey:@"first"];
    [arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    SKTag *tag = [[SKTag alloc] initWithText:arr[idx]];
    tag.font = [UIFont systemFontOfSize:12];
    tag.textColor = [UIColor colorWithRed:arc4random() % 256 / 255.0 green:arc4random() % 256 / 255.0 blue:arc4random() % 256 / 255.0 alpha:1];
    tag.bgColor =[UIColor colorWithRed:arc4random() % 256 / 255.0 green:arc4random() % 256 / 255.0 blue:arc4random() % 256 / 255.0 alpha:1];
    tag.cornerRadius = 5;
    tag.enable = YES;
    tag.padding = UIEdgeInsetsMake(5, 10, 5, 10);
    [cell.tagView addTag:tag];
    }
    ];
    cell.tagView.didTapTagAtIndex = ^(NSUInteger index) {
    NSLog(@"点击了%ld",index);
    }
    ;
    }
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return [tableView fd_heightForCellWithIdentifier:identyfy configuration:^(id cell) {
    [self configCell:cell indexpath:indexPath];
    }
    ];
    }


 

差不多两个简单的Demo就介绍到这里了,再提一点东西,原作者是没有固定宽度这个属性的,没办法,自己动手丰衣足食了,我改了下源码,主要加了两个字段,默认是0,那么出来的效果就是不规则的,宽度随文字而变化,如果赋值这两个字段,那么就是固定宽高,上面已经给出了效果图

 

    @property (assign, nonatomic) CGFloat regularWidth;
    //!< 固定宽度@property (nonatomic,assign ) CGFloat regularHeight;
    //!< 固定高度

给BOOL属性进行复赋值

 

 

    @interface SKTagView ()@property (strong, nonatomic, nullable) NSMutableArray *tags;
    @property (assign, nonatomic) BOOL didSetup;
    @property (nonatomic,assign) BOOL isIntrinsicWidth;
    //!<是否宽度固定@property (nonatomic,assign) BOOL isIntrinsicHeight;
    //!<是否高度固定@end@implementation SKTagView// 重写setter给bool赋值- (void)setRegularWidth:(CGFloat)intrinsicWidth{
    if (_regularWidth != intrinsicWidth) {
    _regularWidth = intrinsicWidth;
    if (intrinsicWidth == 0) {
    self.isIntrinsicWidth = NO;
    }
    else {
    self.isIntrinsicWidth = YES;
    }
    }
    }

 

 

主要在下面这个放里面引入了两个判断

 

CGFloat width1 = self.isIntrinsicWidth?self.regularWidth:size.width;

CGFloat height1 = self.isIntrinsicHeight?self.regularHeight:size.height;

    #pragma mark - Private- (void)layoutTags {
    if (self.didSetup || !self.tags.count) {
    return;
    }
    NSArray *subviews = self.subviews;
    UIView *previousView = nil;
    CGFloat topPadding = self.padding.top;
    CGFloat leftPadding = self.padding.left;
    CGFloat rightPadding = self.padding.right;
    CGFloat itemSpacing = self.interitemSpacing;
    CGFloat lineSpacing = self.lineSpacing;
    CGFloat currentX = leftPadding;
    if (!self.singleLine && self.preferredMaxLayoutWidth > 0) {
    for (UIView *view in subviews) {
    CGSize size = view.intrinsicContentSize;
    CGFloat width1 = self.isIntrinsicWidth?self.regularWidth:size.width;
    CGFloat height1 = self.isIntrinsicHeight?self.regularHeight:size.height;
    if (previousView) {
    // CGFloat width = size.width;
    currentX += itemSpacing;
    if (currentX + width1 + rightPadding <= self.preferredMaxLayoutWidth) {
    view.frame = CGRectMake(currentX, CGRectGetMinY(previousView.frame), width1, height1);
    currentX += width1;
    }
    else {
    CGFloat width = MIN(width1, self.preferredMaxLayoutWidth - leftPadding - rightPadding);
    view.frame = CGRectMake(leftPadding, CGRectGetMaxY(previousView.frame) + lineSpacing, width, height1);
    currentX = leftPadding + width;
    }
    }
    else {
    CGFloat width = MIN(width1, self.preferredMaxLayoutWidth - leftPadding - rightPadding);
    view.frame = CGRectMake(leftPadding, topPadding, width, height1);
    currentX += width;
    }
    previousView = view;
    }
    }
    else {
    for (UIView *view in subviews) {
    CGSize size = view.intrinsicContentSize;
    view.frame = CGRectMake(currentX, topPadding, self.isIntrinsicWidth?self.regularWidth:size.width, self.isIntrinsicHeight?self.regularHeight:size.height);
    currentX += self.isIntrinsicWidth?self.regularWidth:size.width;
    previousView = view;
    }
    }
    self.didSetup = YES;
    }

介绍完啦,各位还需要细看的请点击传送门跑起来看看,不早啦,各位晚安~~~~~~

 

OVER~~~~~~


 

相关热词搜索: