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算出行数

原文地址:https://www.cnblogs.com/lijianyi/p/11496476.html

时间: 2024-10-13 23:26:25

iOS 文本展开收起的相关文章

Android 仿小红书自定义展开 收起的TextView

详解 故事是这么开始的,有个产品需求需求,要做一个小红书文本折叠的功能,于是就有了后面一系列的东西.不过实现了之后,自己对 TextView 截取文本也了解了不少,具体效果如下: 先总结一下实现的时候需要注意的几个点: 显示 "-展开" 时,是截取的一定行数之后,在最后一行的末尾直接显示 "收起" 显示在全部文本的下一行,并且是右对齐 展开和收起的动画效果 如果归纳的不完善,还请指出,不想看过程了可以直接跳到文末查看ExpandableTextView代码 文本的截

Javascript展开收起

<!DOCTYPE html><html><head><meta charset="utf-8" /><title>展开收起</title><style type="text/css">body{ margin: 0 auto; padding: 0px;}#pn{ background: #e8e8e8; width: 600px; height: auto; margin: 0

Xamarin iOS文本框视图

Xamarin iOS文本框视图 与标签视图不同,文本框视图(一般使用UITextField类实现)可以接收用户的文本输入,并进行显示. [示例2-16]以下将使用文本框来实现QQ登录界面的效果.具体步骤如下: (1)创建一个Single View Application类型的工程,命名为2-5 (2)打开MainStoryboard.storyboard文件,对主视图进行设置.效果如图2.30所示. 图2.30  主视图 需要添加的视图以及设置如表2-8所示. 表2-8  设置主视图 (3)打

展开收起播放列表

//播放器关闭展开播放列表  by sunhw    (function() {        function PlayFold( option ) {            this.option = T.object.extend( {                root           : '',                foldBtn        : '',                playListLayout : '',                packu

展开-收起

1.需求,展开-收起 html代码: css中默认pr_list"是隐藏的. 一开始js是这样子写的 出现问题:出现的bug,就是只能点击一次,点第二次就不行了. 分析问题:收起来后,那句 "查看楼盘简介" 是我后来手动插进去的,还没有绑定任何事件,与我前面绑定事件的元素,不是一个东西: 解决问题:

JS+CSS实现可展开/收起的QQ在线客服悬浮代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>JS+CSS实现可展开/收起的QQ在线客服

HTML-003-模拟IDE代码展开收起功能简单示例

当先我们在日常的编程开发工作中使用编程工具(例如 Eclipse.Sublime 等等)都有相应的代码折叠展开功能,如下图所示,极大的方便了我们的编码工作. 同时,我们在日常的网页,尤其的广大的博客网站的源码展示部分,都采用了此种显示方式,如下图所示(示例引用位置:008-Selenium 操作下拉列表实例-Select): 这么做的意义何在呢?我觉得其实际应用有如下两种: 内容的展示和隐藏:将用户最关心.感兴趣的内容展示给用户,若用户想继续深入了解,则可通过点击展示或隐藏按钮达到查看.隐藏内容

实现列表展开收起效果

$(".btn").click(function () {$(this).parents("当前元素最外层div的class").toggleClass("showDiv").siblings().removeClass("showDiv");});css:.最外层div class .需要收起展开的div的class{display: none;}.showDiv .需要收起展开的div的class{display: blo

Jquery 展开收起

需求:点击展开显示详细内容,收起后隐藏内容 实现: Index.cshtml 显示 ... ... <tr> <td> <a asp-action="Edit" asp-route-id="@item.Nid" asp-route-lcid="@item.Lcid">编辑</a> | <a asp-action="Delete" asp-route-id="@it