1. 程式人生 > >iOS 主流搜尋介面下的Tag標籤佈局框架,各種樣式任君挑選,包您滿意(SKTagView)

iOS 主流搜尋介面下的Tag標籤佈局框架,各種樣式任君挑選,包您滿意(SKTagView)

每個App的搜尋介面下邊都會有熱門搜尋,歷史搜尋之類的標籤,這裡介紹個框架,可以非常容易實現標籤類的不規則流式佈局,也可以實現固定寬度和高度的佈局,也支援Autolayout,使用起來也是非常舒服。SKTagView原框架下只有根據文字寬度不固定的的模式,那麼如果需求有固定寬高模式的,老規矩,只能改原始碼了.

請看圖:


傳統模式:


TableView cell模式的不規則模式和固定寬高模式:


   

電影放完了,開始簡單介紹下

這裡有兩個能用到的地方(截圖來自淘寶)

   

OK,根據以上兩個用途,寫了兩個簡單的Demo,無需再繁瑣的計算了,直接匯入

SKTagView來進行佈局,非常簡單

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>(
//                                <UISearchBarBackground: 0x7ffba1c670e0; frame = (0 0; 360 44); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7ffba1c201a0>>,
//                                <UISearchBarTextField: 0x7ffba1c905b0; frame = (0 0; 0 0); text = ''; clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x7ffba1c90360>>,
//                                <UINavigationButton: 0x7ffba1c982c0; frame = (0 0; 53 30); opaque = NO; layer = <CALayer: 0x7ffba1c98800>>
//                                )
    
    
//    
//    (lldb) po self.searchBar.subviews
//    <__NSArrayM 0x7ffba1e77280>(
//                                <UIView: 0x7ffba1c8a470; frame = (0 0; 360 44); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x7ffba1c7ddc0>>
//                                )
    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;
}
介紹完啦,各位還需要細看的請點選傳送門跑起來看看,不早啦,各位晚安~~~~~~