iOS 文本展開收起


經常會遇到類似微信的展開收起,本身這個邏輯是比較清晰的,動態變換文本的高度就可以,但實際操作過程中,卻會有各種坑,最令人蛋疼的就是抖動,下面簡述下自己的采坑之路

一、給定文本一個限定高度(比如:90),小於等於90就取90,大於90默認收起,點擊展開取真實高度,點擊收起,取90。這樣的做法是直接拿到內容就計算出高度,變高度。

以下5種方法經測驗方案5抖動最小屬於偶發性質且很不明顯(抖動的根本原因在於文本的高度是可變的,在偶發情況下可能剛好使cell的高度在一個臨界值:比如差零點幾個像素之類的,然后微調,就會影響lale,因為別的都是明確的固定值,只有這個是小數后好幾位

1、使用文本的boundingRectWithSize計算文本高度

2、使用字體、行間距計算文本高度(本質是由boundingRectWithSize算出行數然后再算出高度)

3、使用YYTextLayout計算文本高度(本質是自己繪制)

4、使用屬性字符串計算高度

5、使用viewsystemLayoutSizeFittingSize 或者 sizeThatFits獲取高度(獲取到的就是真實展示時的高度)。

     5-1、iOS11之后可以直接在賦值方法里獲取高度(因為iOS11之后,UITableView會先走

              -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;再走 

               - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;即先賦值再算高度---類似安卓。

               而在iOS11之前是先走高度再賦值的,所以才     有一直以來的算高度哈)。

     5-2、拿到數據后創建一個跟展示lable一樣的lable,賦值然后獲取高度

#import <YYKit/NSAttributedString+YYText.h>
@implementation NSString (Size)

//  1、-------------直接計算文本高度--------
+ (CGFloat)getStrH:(CGFloat ) maxW Str:(NSString *)str andFont:(NSInteger) font
{
    if (!str.length) return 0;
    CGRect itemFrame = [str boundingRectWithSize:CGSizeMake(maxW, CGFLOAT_MAX) options: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading  attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:font]} context:nil];
    return  itemFrame.size.height;
    
}
//  向上取整高度
+ (CGFloat)getStrCeilH:(CGFloat ) maxW Str:(NSString *)str andFont:(NSInteger) font
{
    if (!str.length) return 0;
    CGRect itemFrame = [str boundingRectWithSize:CGSizeMake(maxW, CGFLOAT_MAX) options: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading  attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:font]} context:nil];
    CGSize size = itemFrame.size;
//    一定程度能夠防止減輕抖動
    return ceil(size.height);
    
}


//  2、-----------根據字體、行間距和constrainedWidth計算文本高度--------
- (CGFloat)getStrH:(UIFont*)font
       lineSpacing:(CGFloat)lineSpacing
  constrainedWidth:(CGFloat)constrainedWidth {
    
    if (!self.length) {
        return 0;
    }
    CGFloat oneLineHeight = font.lineHeight;
    CGSize textSize = [self boundingRectWithSize:CGSizeMake(constrainedWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil].size;
    
    CGFloat rows = textSize.height / oneLineHeight;
    CGFloat realHeight = (rows * oneLineHeight) + (rows - 1) * lineSpacing;
    return  realHeight;
}

// 有行間距 向上取整高度
- (CGFloat)getStrCeilH:(UIFont*)font
       lineSpacing:(CGFloat)lineSpacing
  constrainedWidth:(CGFloat)constrainedWidth {
    
    if (!self.length) {
        return 0;
    }
    CGFloat oneLineHeight = font.lineHeight;
    CGSize textSize = [self boundingRectWithSize:CGSizeMake(constrainedWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil].size;
    
    CGFloat rows = textSize.height / oneLineHeight;
    CGFloat realHeight = (rows * oneLineHeight) + (rows - 1) * lineSpacing;
    return  ceil(realHeight);
}

- (CGFloat)getStrH:(UIFont*)font
       lineSpacing:(CGFloat)lineSpacing
  constrainedWidth:(CGFloat)constrainedWidth
         limitRows:(NSInteger) limitRows{
    
    if (!self.length) {
        return 0;
    }
    CGFloat oneLineHeight = font.lineHeight;
    CGSize textSize = [self boundingRectWithSize:CGSizeMake(constrainedWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil].size;
    
    CGFloat rows = textSize.height / oneLineHeight;
    if (limitRows > 0 && rows > limitRows) {
        rows = limitRows;
    }
    CGFloat realHeight = (rows * oneLineHeight) + (rows - 1) * lineSpacing;
    return  realHeight;
}

// 3、-------YYTextLayout 使用frame計算准確 自動布局會有誤差--------
- (YYTextLayout*)getYYTextLyout:(UIFont*)font
                    lineSpacing:(CGFloat)lineSpacing
            constrainedWidth:(CGFloat)constrainedWidth {
    if (!self.length) {
        return 0;
    }
    NSMutableAttributedString *attriStr = [[NSMutableAttributedString alloc] initWithString:self];
    attriStr.lineSpacing = lineSpacing;
    attriStr.font = font;
//    attriStr.lineBreakMode = NSLineBreakByTruncatingTail;
    CGSize maxSize = CGSizeMake(constrainedWidth, MAXFLOAT);
    YYTextLayout *contentLayout = [YYTextLayout layoutWithContainerSize:maxSize text:attriStr];
    return  contentLayout;
}
 // 5-1示例
//    CGSize textSize = [self.textContentL systemLayoutSizeFittingSize:CGSizeMake(self.contentView.frame.size.width-20, 1000)];
     CGSize textSize = [self.textContentL sizeThatFits:CGSizeMake(self.contentView.frame.size.width-20, 1000)];
    self.model.height = textSize.height+181+height_collectionview;
// 5-2示例
-(void)setIsShowMore:(BOOL)isShowMore {
    _isShowMore = isShowMore;
    UILabel *temp = [[UILabel alloc] init];
    temp.text = self.textContent;
    temp.font = [UIFont systemFontOfSize:15 weight:(UIFontWeightLight)];
    [temp setColumnSpace:2.0];
    [temp setRowSpace:5];
    //    temp.numberOfLines = 0;
    if (isShowMore) {
        temp.numberOfLines = 0;
    } else {
        temp.numberOfLines = 3;
    }
    CGFloat w = [UIScreen mainScreen].bounds.size.width - 20;
    CGFloat h = MAXFLOAT;
    CGFloat height = ceil([temp sizeThatFits:CGSizeMake(w, h)].height);
    //    NSDictionary *dict = @{NSFontAttributeName: [UIFont systemFontOfSize:17]};
    //    CGFloat height = [title boundingRectWithSize:CGSizeMake(w, h) options:NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil].size.height;
    self.height = height+181+300;
}

二、給文本一個固定行數(比如:3行),小於等於3行,正常顯示,大於3行默認3行,點擊展開真實行數,點擊收起3行。這種方案要結合UITableView的高度自適應UITableViewAutomaticDimension

_tableView.rowHeight = UITableViewAutomaticDimension;

_tableView.estimatedRowHeight = 50; // 這個給不給都可以

)。這樣就不再關心- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;方法。完全讓系統自動調整

。這樣的效果取決於計算出行數的方法。下面簡述兩種方式,方案不唯一,只要能換算出行數就可以。實測方案一效果跟變高度的方案5效果相似,比較理想。

1、使用systemLayoutSizeFittingSize/sizeThatFits獲取行數

//獲取文字所需行數
- (NSInteger)needLinesWithWidth:(CGFloat)width currentLabel:(UILabel *)currentLabel {
    UILabel *label = [[UILabel alloc] init];
    label.font = currentLabel.font;
    NSString *text = currentLabel.text;
    NSInteger sum = 0;
    //加上換行符
    NSArray *rowType = [text componentsSeparatedByString:@"\n"];
    for (NSString *currentText in rowType) {
        label.text = currentText;
        //獲取需要的size
//        CGSize textSize = [label systemLayoutSizeFittingSize:CGSizeZero];
        CGSize textSize = [label sizeThatFits:CGSizeZero];
        NSInteger lines = ceil(textSize.width/width);
        lines = lines == 0 ? 1 : lines;
        sum += lines;
    }
    return sum;
}

2、使用boundingRectWithSize算出行數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM