根据 UILabel 动态调整 uitableViewCell 大小(带段落间距)

Posted

技术标签:

【中文标题】根据 UILabel 动态调整 uitableViewCell 大小(带段落间距)【英文标题】:Dynamically size uitableViewCell according to UILabel (With paragraph spacing) 【发布时间】:2013-10-06 23:34:43 【问题描述】:

我有一个 UITableView,它由 JSON 文件中的文本和图像填充。对于文本中不包含许多换行符的“帖子”,TableView 单元目前的大小正确,但是我无法让它计算具有 4 或 5 个换行符的“帖子”的正确高度。

获取身高代码:

-(float)height :(NSMutableAttributedString*)string

  NSString *stringToSize = [NSString stringWithFormat:@"%@", string];

  CGSize constraint = CGSizeMake(LABEL_WIDTH - (LABEL_MARGIN *2), 2000.f);

  CGSize size = [stringToSize sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:contraint lineBreakMode:NSLineBreakByWordWrapping];

  return size.height;

如何在允许换行和空白的同时计算正确的大小?

编辑

方法的其余部分,

TableView CellForRow 内部:

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

NSString *row = [NSString stringWithFormat:@"%i", indexPath.row];

float postTextHeight = [self height:postText];

NSString *height = [NSString stringWithFormat:@"%f", heightOfPostText + 70];

[_cellSizes setObject:height forKey:row];

以及表格单元格的高度:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

NSString *imageHeightString = [NSString stringWithFormat:@"%@", [_cellSizes objectForKey:indexPath.row]];

float heightOfCell = [imageHeightString floatValue];

 if (heightOfCell == 0) 
    
    return 217;
;

return heightOfCell + 5;

【问题讨论】:

在您的 -tableView:heightForRowAtIndexPath 方法中,您从第一行的哪里获取 indexRow?你是说 indexPath.row 吗? 另外,就像 Timothy 提到的,您需要确保您使用的 UILabel 的 numberOfLines 属性设置为 0。 大家好,我已经添加了 numberOfLines 和 SizeToFit... 还将问题更正为“indexPath.row”。它仍然没有给我正确的高度。但是 _CellSizes 数组给了我正确的高度值。 您的代码似乎应该可以工作。您的表格视图是否有可能是分组样式?有多个部分的那个?此外,您的表格视图外观的屏幕截图可能会有所帮助。 【参考方案1】:

最好先计算高度,方法中不要包含高度计算部分:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

最好用方法计算:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 

因为你是从 json 获取数据,所以你很容易计算 在“heightForRowAtIndexPath”方法中。

下面的代码将给出计算文本高度的例子,改变你的要求。 希望这对你有帮助:)

// i am using an array 
- (void)viewDidLoad

   [super viewDidLoad]; 
   // Do any additional setup after loading the view, typically from a nib.

   UIFont *labelFont = [UIFont fontWithName:@"Noteworthy-Bold" size:20];
   NSDictionary *arialdict = [NSDictionary dictionaryWithObject:labelFont forKey:NSFontAttributeName];

   NSMutableAttributedString *message = [[NSMutableAttributedString alloc] initWithString:@"this is just the sample example of how to calculate the dynamic height for tableview cell which is of around 7 to 8 lines. you will need to set the height of this string first, not seems to be calculated in cellForRowAtIndexPath method." attributes:arialdict];

   array = [NSMutableArray arrayWithObjects:message, nil];
   NSMutableAttributedString *message_1 = [[NSMutableAttributedString alloc] initWithString:@"you will need to set the height of this string first, not seems to be calculated in cellForRowAtIndexPath method." attributes:arialdict];
  [array addObject:message_1];   


 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 
     return 2;
 

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 
     return 2;
 


 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

   UITableViewCell *Cell = [self.aTableView dequeueReusableCellWithIdentifier:@"cell"];
   if(Cell == nil)
    
       Cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
     

     //dont include the height calculation part hear, becz heights are already set for all the cell 
    [Cell.textLabel sizeToFit];
    Cell.textLabel.attributedText = [array objectAtIndex:indexPath.row]; // dont calculate height hear it will be called after "heightForRowAtIndexPath" method
    Cell.textLabel.numberOfLines = 8;
    return Cell;
 

  // put ur height calculation method i took some hardcoded values change it :)
  -(float)height :(NSMutableAttributedString*)string
 
    /*
      NSString *stringToSize = [NSString stringWithFormat:@"%@", string]; 
  // CGSize constraint = CGSizeMake(LABEL_WIDTH - (LABEL_MARGIN *2), 2000.f);
     CGSize maxSize = CGSizeMake(280, MAXFLOAT);//set max height //set the constant width, hear MAXFLOAT gives the maximum height

     CGSize size = [stringToSize sizeWithFont:[UIFont systemFontOfSize:20.0f] constrainedToSize:maxSize lineBreakMode:NSLineBreakByWordWrapping];
return size.height; //finally u get the correct height
    */
     //commenting the above code because "sizeWithFont: constrainedToSize:maxSize: lineBreakMode: " has been deprecated to avoid above code use below

    NSAttributedString *attributedText = string;
    CGRect rect = [attributedText boundingRectWithSize:(CGSize)225, MAXFLOAT
                           options:NSStringDrawingUsesLineFragmentOrigin
                              context:nil];//you need to specify the some width, height will be calculated
    CGSize requiredSize = rect.size;
    return requiredSize.height; //finally u return your height



- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 
     //whatever the height u need to calculate calculate hear only    
     CGFloat heightOfcell = [self height:[array objectAtIndex:indexPath.row]];
     NSLog(@"%f",heightOfcell);
     return heightOfcell;
 

希望这对你有帮助:)

对于SWIFT版本

class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate 


var messageArray:[String] = [] //array to holde the response form son for example 
override func viewDidLoad()

    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    messageArray = ["One of the most interesting features of Newsstand is that once an asset downloading has started it will continue even if the application is suspended (that is: not running but still in memory) or it is terminated. Of course during while your app is suspended it will not receive any status update but it will be woken up in the background",
                    "In case that app has been terminated while downloading was in progress, the situation is different. Infact in the event of a finished downloading the app can not be simply woken up and the connection delegate finish download method called, as when an app is terminated its App delegate object doesn’t exist anymore. In such case the system will relaunch the app in the background.", 
                    " If defined, this key will contain the array of all asset identifiers that caused the launch. From my tests it doesn’t seem this check is really required if you reconnect the pending downloading as explained in the next paragraph.",
                    ]


func numberOfSectionsInTableView(tableView: UITableView) -> Int

    return 1;


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int

    return messageArray.count;


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

    var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? UITableViewCell;
    if(cell == nil)
    
        cell = UITableViewCell(style:UITableViewCellStyle.Default, reuseIdentifier: "CELL")
        cell?.selectionStyle = UITableViewCellSelectionStyle.None
    
    cell?.textLabel.font = UIFont.systemFontOfSize(15.0)
    cell?.textLabel.sizeToFit()
    cell?.textLabel.text = messageArray[indexPath.row]
    cell?.textLabel.numberOfLines = 0
    return cell!;


func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat

    var height:CGFloat = self.calculateHeightForString(messageArray[indexPath.row])
    return height + 70.0


func calculateHeightForString(inString:String) -> CGFloat

    var messageString = inString
    var attributes = [UIFont(): UIFont.systemFontOfSize(15.0)]
    var attrString:NSAttributedString? = NSAttributedString(string: messageString, attributes: attributes)
    var rect:CGRect = attrString!.boundingRectWithSize(CGSizeMake(300.0,CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, context:nil )
    var requredSize:CGRect = rect
    return requredSize.height  //to include button's in your tableview

 

【讨论】:

【参考方案2】:

@Shan 有一个很好的答案,但它并不完全适合我。

这是我用来计算单元格高度的代码

-(float)height :(NSMutableAttributedString*)string

    CGRect rect = [string boundingRectWithSize:(CGSize)table.frame.size.width - 110, MAXFLOAT options:NSStringDrawingUsesLineFragmentOrigin context:nil];
    return rect.size.height;

我使用 -110 是因为这样可以在顶部和底部提供相等的空间。

希望这会有所帮助。

【讨论】:

是的,我选择了一些硬编码值,“boundingRectWithSize”你可以像在你的代码中一样使用。上面我只是举个例子【参考方案3】:

实现这个表视图委托方法:

-tableView:heightForRowAtIndexPath:

https://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:heightForRowAtIndexPath:

如果需要,您将调用确定高度的方法并返回该值并使用一些额外的填充。

【讨论】:

嗨,马特,请参阅更新后的问题。我目前正在使用 tableView:heightForRow :)【参考方案4】:

我推荐的方法是设置实际标签的文本并通过调用sizeToFit 获得所需的高度。为此,您必须将标签的 numberOfLines 属性设置为 0 并设置所需的最大宽度。

当将此技术用于表格视图时,您可以使用prototype cell method discussed here 来使用实际单元格计算高度。

【讨论】:

以上是关于根据 UILabel 动态调整 uitableViewCell 大小(带段落间距)的主要内容,如果未能解决你的问题,请参考以下文章

带有 2 个 UILabel 的 UIStackview 可以根据内容动态调整吗?

根据 UILabel 动态调整 uitableViewCell 大小(带段落间距)

UILabel 动态内容自动调整大小问题

根据文本调整 UILabel 高度

以编程方式动态调整多行 UILabel 和随附的表格视图单元格

无论文本如何,UILabel 都会将高度调整为 0