以编程方式动态更改单元格高度

时间:2015-08-13 08:59:58

标签: objective-c uitableview parse-platform pfquery heightforrowatindexpath

我在SO上尝试了很多答案,但没有真正有效。我可能做错了所以我需要有人指出我做错了什么..

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

    NSLog(@"text : %@", self.cell.comment.text);

    NSString *text = self.cell.comment.text;
    CGFloat width = self.cell.frame.size.width;
    UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:15];
    NSAttributedString *attributedText =
    [[NSAttributedString alloc] initWithString:text
                                    attributes:@{NSFontAttributeName: font}];
    CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                               context:nil];
    CGSize size = rect.size;
    CGFloat height = ceilf(size.height);

    return height;
}

我得到“NSInvalidArgumentException”,原因是“NSConcreteAttributedString initWithString :: nil value”因为self.cell.comment.text在我设置单元格高度时没有得到任何东西但它确实通过了只是不在调用heightForRowAtIndexPath时。

很多人评论说这个方法运行得很好所以我想我错过了什么?

修改

我在这里设置self.cell.comment.text -

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object{
static NSString *simpleTableIdentifier = @"cell";

self.cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (self.cell == nil) {
    self.cell = [[CommentCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}

// Configure the cell

self.cell.comment.text = [object objectForKey:@"comment"];
[self.cell.comment sizeToFit];

return self.cell;}

3 个答案:

答案 0 :(得分:4)

您已经评论的问题是在填充单元格之前调用函数heightForRowAtIndexPath

对于每个可见的单元格,首先调用

  • 获取此单元格的高度
  • 填充单元格

所以你知道

a)您的文字尚未填充在单元格

上 b)其他一些文本可能在里面,因为苹果使用可重复使用的单元格,因此UITableView可以抓取一些单元格(使用不同的文本)并尝试调整它的大小然后填充它。

在你的情况下,它将获取一些其他文本,将单元格大小调整为其大小,然后使用其他文本(可能)与之前的文本大小不同来填充它。

但是在细胞群体中,您可以从某些业务逻辑(可能是数组?)设置文本,并且您可以在此方法中获得相同的文本。

如果您调用的细胞数量

cell.comment.text = [self.someArray getObjectAtIndex:index.row];

您可以使用heightForRowAtIndexPath方法调用此方法。

NSString *text = [self.someArray getObjectAtIndex:index.row];

我看到您的编辑只是致电:

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

NSLog(@"text : %@", self.cell.comment.text);

NSString *text = [object objectForKey:@"comment"];;
CGFloat width = self.cell.frame.size.width;
UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:15];
NSAttributedString *attributedText =
[[NSAttributedString alloc] initWithString:text
                                attributes:@{NSFontAttributeName: font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
CGSize size = rect.size;
CGFloat height = ceilf(size.height);

return height;
}

附加:

电话说你想要这样的小区:

-------------------------
|  bla bla bla         |
------------------------
| second longer text   |
| over more line       |
------------------------

您需要在某处保存文本bla bla和“更长行的第二个文字”。

假设您有大小为2的数组。

NSArray * myTextArray = @[@"bla bla", @"second longer text over more line"];

填充单元格时

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object{
   static NSString *simpleTableIdentifier = @"cell";

   self.cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
   if (self.cell == nil) {
        self.cell = [[CommentCell alloc] initWithStyle:UITableViewCellStyleDefault         reuseIdentifier:simpleTableIdentifier];
    }

    // Configure the cell

    self.cell.comment.text = [myTextArray objectAtIndex:indexPath.row];
    [self.cell.comment sizeToFit];

    return self.cell;
 }

因为在heightForRowAtIndexPath之前调用了cellForRowAtIndexPath我们需要检查业务(数组)方面的文本而不是视觉文本。

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

   NSLog(@"text : %@", self.cell.comment.text); // -> this is null because cell is not populated yet.

   NSString *text = [myTextArray objectAtIndex:indexPath.row]; -> this is same text as we will take when populating cell and is not random.
   CGFloat width = self.cell.frame.size.width;
   UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:15];
   NSAttributedString *attributedText =
   [[NSAttributedString alloc] initWithString:text
                                attributes:@{NSFontAttributeName: font}];
   CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
   CGSize size = rect.size;
   CGFloat height = ceilf(size.height);

   return height;
}

示例:

#import "ViewController.h"

@interface ViewController ()

@property NSArray * myArray;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.myArray = @[@"Some short text",@"Some longer text that take some more space throw more lines",@"bfusdbfjdsfjs fj yfsdy fgsydu fyudsfy fyudsyu fdsy fuysdyuf ydsug fyu sdgyfgsuyff ius fhs fiusdhi ufdshu uifsd ufsdh hfiuds uifdsh fsduih ufdshu hfsd ifshui"];

}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 3;
}


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

    NSString *text = self.myArray[indexPath.row];
    CGFloat width = 300;
    UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:15];
    NSAttributedString *attributedText =
    [[NSAttributedString alloc] initWithString:text
                                attributes:@{NSFontAttributeName: font}];
    CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
    CGSize size = rect.size;
    CGFloat height = ceilf(size.height);

    return height;
}

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

    static NSString *simpleTableIdentifier = @"cell";

    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
    }

    // Configure the cell

    cell.textLabel.text = self.myArray[indexPath.row];
    cell.textLabel.numberOfLines = 0;
    return cell;
}

此示例有效。

答案 1 :(得分:0)

在heightForRowAtIndexPath中:

对于宽度,我认为你可以解决它,并且不需要这一行:

 CGFloat width = self.cell.frame.size.width;

评论文字

NSString *text = self.cell.comment.text;

试试这个

NSString *text = [object objectForKey:@"comment"];

答案 2 :(得分:0)

花了一整天试图解决这个问题,最后发现解决方案非常简单,我只需要知道如何更好地使用Parse。

感谢Marko,我已经了解了UITableView是如何运作的,这很棒但是我的问题的解决方案有点不同。

正如大家所说,我的问题是假设在填充所有单元格后调用heightForRowAtIndexPath但我不需要数组来保存对象或进行任何更改。 Parse显然会在调用heightForRowAtIndexPath之前保存所有检索到的对象,并且它们全部在 self.objects 中。

self.cell.comment.text = [self.objects objectAtIndex:indexPath.row];

Andy热情地建议,我现在正在使用Auto-size UITableViewCell。

在您的PFQueryTableViewController

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

PFObject *object = [self.objects objectAtIndex:indexPath.row];

if (object) {
    NSString *commentString = [self.objects[indexPath.row] objectForKey:@"comment"];

    NSLog(@"commentString : %@",commentString);

    CommentCell *cell = [[CommentCell alloc] init];
    cell.textLabel.text = commentString;


    [cell setNeedsLayout];
    [cell layoutIfNeeded];

    self.height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    self.height += 1;

}

return self.height;}

在您的CustomCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {

    self.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
    self.textLabel.numberOfLines = 0;
    self.textLabel.translatesAutoresizingMaskIntoConstraints = NO;


    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-6-[bodyLabel]-6-|" options:0 metrics:nil views:@{ @"bodyLabel": self.textLabel }]];
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-6-[bodyLabel]-6-|" options:0 metrics:nil views:@{ @"bodyLabel": self.textLabel }]];

}

return self;}


 - (void)layoutSubviews{
[super layoutSubviews];

[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];

self.textLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.textLabel.frame);}

这肯定有效。