Cell自適應(yīng)高度標(biāo)簽

前言

好久沒有更新自己的博客了碟刺,去年自己在博客總結(jié)說到自己要堅持更新博客,不管是否有技術(shù)含量除抛,都要持之以恒狮杨,無論做什么,都貴在堅持到忽,我希望通過寫博客能積累自己的技術(shù)與經(jīng)驗橄教。不多說了,言歸正傳喘漏,下面開始介紹我是如何實現(xiàn)Cell標(biāo)簽自適應(yīng)的吧护蝶。

一、本地數(shù)據(jù)自適應(yīng)

  • 在做項目意見反饋的時候翩迈,需要選擇反饋類型持灰,整個界面是UITableView,我現(xiàn)在喜歡用自動布局负饲,用的Masonry布局框架堤魁,開始選擇類型是放在本地的,用Masonry實現(xiàn)cell高度自適應(yīng)還算相對簡單的返十,下面是實現(xiàn)數(shù)據(jù)在本地高度自適應(yīng)的核心代碼妥泉,該方法在cell初始化方法中調(diào)用:
- (void)initSubviews {
    /** << init subviews > */
    CGFloat margin = 15.f;
    CGFloat spacing = 10.f;
    CGFloat maxWidth = ScreenWidth;
    __block CGFloat rowWidth = 0;
    __block BOOL isNeedChangeLine = YES;
    __block UIButton *lastButton = nil;
    NSInteger count = self.dataArray.count;
    [self.dataArray enumerateObjectsUsingBlock:^(CYBImageTitleModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.titleLabel.font = FONT(14.f);
        button.adjustsImageWhenHighlighted = NO;
        [button setTitleColor:[UIColor lightGrayColor]
                     forState:UIControlStateNormal];
        [button setTitleColor:Color_Orange
                     forState:UIControlStateSelected];
        [button setBackgroundImage:obj.image
                          forState:UIControlStateNormal];
        [button setBackgroundImage:obj.selectedImage
                          forState:UIControlStateSelected];
        [button setTitle:obj.title
                forState:UIControlStateNormal];
        button.tag = kBTN_TAG + idx;
        button.selected = obj.isSelected;
        if (obj.isSelected) {
            tempBtn = button;
        }
        [button wb_addTarget:self action:@selector(buttonClicked:)];
        
        [self.contentView addSubview:button];

        CGFloat titleWidth = [obj.title boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 28)
                                                     options:NSStringDrawingUsesLineFragmentOrigin
                                                  attributes:@{NSFontAttributeName : FONT(14.f)} context:nil].size.width + 2 * 8;
        rowWidth += titleWidth + spacing;
        /** < 是否需要換行 >  */
        if (rowWidth > maxWidth - 2 * margin) {
            isNeedChangeLine = YES;
            /** < 判斷是否超過最大值 >  */
            if (titleWidth + 2 * margin > maxWidth) {
                titleWidth = maxWidth - 2 * margin;
            }
            /** < 換行后重新設(shè)置當(dāng)前行的總寬度 >  */
            rowWidth = titleWidth + spacing;
        }
        
        [button mas_makeConstraints:^(MASConstraintMaker *make) {
            /** < 換行 >  */
            if (isNeedChangeLine) {
                if (!lastButton) {
                    make.top.equalTo(self.contentView.mas_top).offset(margin);
                }else {
                    make.top.equalTo(lastButton.mas_bottom).offset(spacing);
                }
                make.left.equalTo(self.contentView.mas_left).offset(margin);
                isNeedChangeLine = NO;
            }else {
                make.left.equalTo(lastButton.mas_right).offset(spacing);
                make.top.equalTo(lastButton.mas_top);
            }
            make.height.mas_equalTo(@(28));
            make.width.mas_equalTo(@(titleWidth));
            
            /** < 最后一個 >  */
            if (idx == count - 1) {
                make.bottom.equalTo(self.contentView.mas_bottom).offset(-margin);
            }
        }];
        lastButton = button;
    }];
}

二、網(wǎng)絡(luò)請求數(shù)據(jù)高度自適應(yīng)

  • 后來改需求了吧慢,需要從網(wǎng)絡(luò)請求意見反饋類型涛漂,好吧,上面的方法已經(jīng)有實現(xiàn)高度自適應(yīng)關(guān)鍵代碼了检诗,只要稍作修改就可實現(xiàn)了匈仗。但是實現(xiàn)過程并不是想象中那么簡單,中間也經(jīng)理了很多波折逢慌。因為時間還是很充裕的悠轩,我就考慮到將標(biāo)簽空間封裝成一個視圖,等要使用的時候自己添加到cell上攻泼,并設(shè)置上下左右約束火架,封裝完成之后并沒有達(dá)到我想要的效果,我發(fā)現(xiàn)cell根本就撐不起來忙菠,我檢查了一遍約束何鸡,上下左右約束沒有遺漏呀,封裝的視圖WBAutoTagListView核心代碼如下牛欢,約束實在layoutSubviews設(shè)置的:
#pragma mark < Layout >
- (void)layoutSubviews {
    [super layoutSubviews];
    
    CGFloat maxWidth = self.bounds.size.width - _secionInset.left - _secionInset.right;
    __block CGFloat rowWidth = 0;
    __block BOOL isNeedChangeLine = YES;
    __block WBTagListItem *lastItem = nil;
    NSInteger count = self.itemArray.count;
    [self.itemArray enumerateObjectsUsingBlock:^(WBTagListItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        CGFloat titleWidth = obj.titleWidth;
        rowWidth += titleWidth + _minimumInteritemSpacing;
         /** < 是否需要換行 >  */
        if (rowWidth > maxWidth - 2 * _minimumInteritemSpacing) {
            isNeedChangeLine = YES;
            /** < 判斷是否超過最大值 >  */
            if (titleWidth + 2 * _minimumInteritemSpacing > maxWidth) {
                titleWidth = maxWidth - 2 * _minimumInteritemSpacing;
            }
            /** < 換行后重新設(shè)置當(dāng)前行的總寬度 >  */
            rowWidth = titleWidth + _minimumInteritemSpacing;
        }
        [obj mas_makeConstraints:^(MASConstraintMaker *make) {
            /** < 換行 >  */
            if (isNeedChangeLine) {
                if (!lastItem) {
                    make.top.equalTo(self.mas_top).offset(_secionInset.top);
                }else {
                    make.top.equalTo(lastItem.mas_bottom).offset(_minimumLineSpacing);
                }
                make.left.equalTo(self.mas_left).offset(_secionInset.left);
                isNeedChangeLine = NO;
            }else {
                make.left.equalTo(lastItem.mas_right).offset(_minimumInteritemSpacing);
                make.top.equalTo(lastItem.mas_top);
            }
            make.height.mas_equalTo(@(_itemHeight));
            make.width.mas_equalTo(@(titleWidth));
            
            /** < 最后一個 >  */
            if (idx == count - 1) {
                make.bottom.mas_offset(-_secionInset.bottom).priorityMedium();
            }
        }];
        lastItem = obj;
    }];
    NSLog(@"%f",[self systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height);
}
  • 經(jīng)測試骡男,將該視圖添加到控制器的視圖上是可以自適應(yīng)高度的,但是添加的cell上傍睹,就無法撐cell高度隔盛,嘗試了許多寫法,還是未能實現(xiàn)拾稳,控制臺提示了無法算出cell的高度吮炕,就給了一個默認(rèn)高度,頓時都無語了访得,有知道的大神能告訴我為什么有內(nèi)容卻無法撐起cell高度嗎龙亲?
  • 既然封裝的視圖無法實現(xiàn)cell高度自適應(yīng),我就嘗試另外的思路方法悍抑,既然是cell自適應(yīng)鳄炉,那就索性封裝一個標(biāo)簽cell吧WBTagListViewCell,為了可復(fù)用性传趾,也為WBTagListViewCell添加了一些配置屬性迎膜,如下:
/** < 數(shù)據(jù)源 > */
@property (nonatomic, strong) NSArray <WBTagListModel *>*items;
/** < 內(nèi)邊距 默認(rèn): UIEdgeInsetsMake(15, 15, 15, 15) > */
@property (nonatomic, assign) UIEdgeInsets secionInset;
/** < 行間距 默認(rèn):15 > */
@property (nonatomic, assign) CGFloat minimumLineSpacing;
/** < item之間距離 默認(rèn):10 > */
@property (nonatomic, assign) CGFloat minimumInteritemSpacing;
/** < 是否允許點擊 默認(rèn):YES > */
@property (nonatomic, assign) BOOL allowSelection;
/** < 是否允許多選 默認(rèn):NO > */
@property (nonatomic, assign) BOOL allowMultipleSelection;
/** < 標(biāo)簽高度 默認(rèn):28.f > */
@property (nonatomic, assign) CGFloat itemHeight;

/** < 標(biāo)簽左右間距 默認(rèn):10.f > */
@property (nonatomic, assign) CGFloat leftRightMargin;
/** < 背景圖片 > */
@property (nonatomic, copy) NSString *bgImageName;
/** < 選中背景圖片 > */
@property (nonatomic, copy) NSString *selectedBgImageName;
/** < 標(biāo)簽顏色 默認(rèn):淺灰色 > */
@property (nonatomic, strong) UIColor *titleColor;
/** < 按鈕選中顏色 > */
@property (nonatomic, strong) UIColor *titleSelectedColor;
/** < 標(biāo)題大小 默認(rèn):14pt > */
@property (nonatomic, strong) UIFont *font;
/** < 邊框?qū)挾?默認(rèn):0 > */
@property (nonatomic, assign) CGFloat borderWidth;
/** < 邊框顏色 bodoerWidth > 0 設(shè)置有效 > */
@property (nonatomic, strong) UIColor *borderColor;
/** < 選中邊框顏色 bodoerWidth > 0 設(shè)置有效 > */
@property (nonatomic, strong) UIColor *selectedBorderColor;
/** < 圓角大小 默認(rèn):0 > */
@property (nonatomic, assign) CGFloat cornerRadius;
/** < 選中的item > */
@property (nonatomic, strong) NSMutableArray *selectedItems;

@property (nonatomic, weak) id <WBTagListViewCellDelegate> delegate;
  • 關(guān)鍵實現(xiàn)步驟是重寫了cell的updateConstraints,在有數(shù)據(jù)源的時候調(diào)用setNeedsUpdateConstraints浆兰,關(guān)鍵代碼如下:
- (void)createTagWithData:(NSArray <WBTagListModel *>*)itemsArray {
    for (UIView *view in self.itemArray) {
        [view removeFromSuperview];
    }
    [self.itemArray removeAllObjects];
    
    for (NSInteger index = 0; index < itemsArray.count; index ++) {
        WBTagListItem *item = [WBTagListItem new];
        item.title = itemsArray[index].title;
        item.isSelected = itemsArray[index].isSelected;
        item.itemTag = index;
        item.delegate = self;
        [self.contentView addSubview:item];
        [self.itemArray addObject:item];
        
        /** < 默認(rèn)選中第一個 > */
        if (index == 0 && itemsArray[index].isSelected) {
            _tempItem = item;
            [self.selectedItems removeAllObjects];
            [self.selectedItems addObject:_tempItem];
        }
    }
    [self setNeedsUpdateConstraints];
}

- (void)updateConstraints {
    [super updateConstraints];
    
    CGFloat maxWidth = self.contentView.bounds.size.width - _secionInset.left - _secionInset.right;
    __block CGFloat rowWidth = 0;
    __block BOOL isNeedChangeLine = YES;
    __block WBTagListItem *lastItem = nil;
    NSInteger count = self.itemArray.count;
    [self.itemArray enumerateObjectsUsingBlock:^(WBTagListItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        CGFloat titleWidth = obj.titleWidth;
        rowWidth += titleWidth + _minimumInteritemSpacing;
        /** < 是否需要換行 >  */
        if (rowWidth > maxWidth - 2 * _minimumInteritemSpacing) {
            isNeedChangeLine = YES;
            /** < 判斷是否超過最大值 >  */
            if (titleWidth + 2 * _minimumInteritemSpacing > maxWidth) {
                titleWidth = maxWidth - 2 * _minimumInteritemSpacing;
            }
            /** < 換行后重新設(shè)置當(dāng)前行的總寬度 >  */
            rowWidth = titleWidth + _minimumInteritemSpacing;
        }
        [obj mas_makeConstraints:^(MASConstraintMaker *make) {
            /** < 換行 >  */
            if (isNeedChangeLine) {
                if (!lastItem) {
                    make.top.equalTo(self.contentView.mas_top).offset(_secionInset.top);
                }else {
                    make.top.equalTo(lastItem.mas_bottom).offset(_minimumLineSpacing);
                }
                make.left.equalTo(self.contentView.mas_left).offset(_secionInset.left);
                isNeedChangeLine = NO;
            }else {
                make.left.equalTo(lastItem.mas_right).offset(_minimumInteritemSpacing);
                make.top.equalTo(lastItem.mas_top);
            }
            make.height.mas_equalTo(@(_itemHeight));
            make.width.mas_equalTo(@(titleWidth));
            
            /** < 最后一個 >  */
            if (idx == count - 1) {
                make.bottom.equalTo(self.contentView.mas_bottom).offset(-_secionInset.bottom).priorityMedium();
            }
        }];
        lastItem = obj;
    }];
}
  • 最后運(yùn)行效果也貼一張圖吧


    Simulator Screen Shot - iPhone X - 2018-06-07 at 23.48.33.png
  • 封裝cell在實現(xiàn)過程中磕仅,也遇到一些問題,最開始把約束寫到layoutSubviews還是無法自適應(yīng)高度簸呈,再就是要考慮到cell復(fù)用的問題榕订。不管怎樣最后還是實現(xiàn)了自己想要的效果,由于技術(shù)有限蜕便,可能我有寫的不對不好的地方劫恒,還請斧正。最后也貼出自動布局和frame布局標(biāo)簽demo,如果覺得對你有幫助两嘴,請Star鼓勵下吧丛楚。

三、GitHub Demo

Auto:WBAutoTagListViewDemo
Frame:WB_TagsViewDemo

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末憔辫,一起剝皮案震驚了整個濱河市趣些,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贰您,老刑警劉巖坏平,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锦亦,居然都是意外死亡舶替,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門杠园,熙熙樓的掌柜王于貴愁眉苦臉地迎上來顾瞪,“玉大人,你說我怎么就攤上這事返劲×崦粒” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵篮绿,是天一觀的道長孵延。 經(jīng)常有香客問我,道長亲配,這世上最難降的妖魔是什么尘应? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮吼虎,結(jié)果婚禮上犬钢,老公的妹妹穿的比我還像新娘。我一直安慰自己思灰,他們只是感情好玷犹,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著洒疚,像睡著了一般歹颓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上油湖,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天巍扛,我揣著相機(jī)與錄音,去河邊找鬼乏德。 笑死臣咖,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的英上。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼矢棚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贷痪?” 一聲冷哼從身側(cè)響起幻妓,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蹦误,失蹤者是張志新(化名)和其女友劉穎劫拢,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體强胰,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舱沧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了偶洋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片熟吏。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖玄窝,靈堂內(nèi)的尸體忽然破棺而出牵寺,到底是詐尸還是另有隱情,我是刑警寧澤恩脂,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布帽氓,位于F島的核電站,受9級特大地震影響俩块,放射性物質(zhì)發(fā)生泄漏黎休。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一玉凯、第九天 我趴在偏房一處隱蔽的房頂上張望势腮。 院中可真熱鬧,春花似錦漫仆、人聲如沸捎拯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽署照。三九已至,卻和暖如春狸眼,著一層夾襖步出監(jiān)牢的瞬間藤树,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工拓萌, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留岁钓,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像屡限,于是被迫代替她去往敵國和親品嚣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容