zoukankan      html  css  js  c++  java
  • 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:@"
    "];
        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算出行数

  • 相关阅读:
    CSV格式的文件与EXCEL文件的区别
    Arcgis 离线部署api 4.x的两种本地部署方法!
    IDEA版部署离线ArcGIS api for JavaScript
    java web中统一结果返回封装类JsonResult
    网络最大流dinic
    Luogu P3834 可持久化线段树2(主席树)
    LuoguP2824[HEOI2016/TJOI2016]排序
    2021.03.24模拟赛DP
    Luogu P3166数三角形
    乘法逆元
  • 原文地址:https://www.cnblogs.com/lijianyi/p/11496476.html
Copyright © 2011-2022 走看看