26

我制作了一个类似 imessage 的视图,只需在底部文本视图中输入文本。我使用表格视图来执行此操作,并使用最后一个单元格中的文本视图。当我输入超过一行的长文本时,我需要文本视图并且单元格变得更细。所以我需要刷新单元格的高度。但是如果我使用表格视图的重新加载或重新加载行,文本视图中的内容会消失,键盘也会消失。有没有更好的方法来修复它?

可能我应该使用工具栏来简单吗?但我仍然怀疑表格视图可以做到这一点。

4

4 回答 4

66

当您调用beginUpdates和时,单元格将平滑调整大小endUpdates。在这些调用之后,tableView 将发送表格tableView:heightForRowAtIndexPath:中的所有单元格,当 tableView 获得所有单元格的所有高度时,它将为调整大小设置动画。

您可以通过直接设置单元格的属性来更新单元格而无需重新加载它们。无需涉及 tableView 和tableView:cellForRowAtIndexPath:

要调整单元格的大小,您将使用与此类似的代码

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text];
    CGSize size = // calculate size of new text
    if ((NSInteger)size.height != (NSInteger)[self tableView:nil heightForRowAtIndexPath:nil]) {
        // if new size is different to old size resize cells. 
        // since beginUpdate/endUpdates calls tableView:heightForRowAtIndexPath: for all cells in the table this should only be done when really necessary.
        [self.tableView beginUpdates];
        [self.tableView endUpdates];
    }
    return YES;
}

要在不重新加载的情况下更改单元格的内容,我使用如下内容:

- (void)configureCell:(FancyCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    MyFancyObject *object = ...
    cell.textView.text = object.text;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    FancyCell *cell = (FancyCell *)[tableView dequeueReusableCellWithIdentifier:@"CellWithTextView"];
    [self configureCell:cell forRowAtIndexPath:indexPath];
    return cell;
}

// whenever you want to change the cell content use something like this:

    NSIndexPath *indexPath = ...
    FancyCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
    [self configureCell:cell forRowAtIndexPath:indexPath];
于 2012-12-28T10:16:33.263 回答
2

我编写了 UITableViewCell 的子类来处理此功能。

.h 文件:

#import <UIKit/UIKit.h>

@protocol AECELLSizeableDelegate;

@interface AECELLSizeable : UITableViewCell

@property (weak, nonatomic) id <AECELLSizeableDelegate> delegate;

@property IBOutlet UIView *viewMinimized;
@property IBOutlet UIView *viewMaximized;
@property BOOL maximized;

@property CGFloat height;

- (IBAction)clickedConfirm:(id)sender;
- (IBAction)clickedCancel:(id)sender;

- (void)minimizeForTableview: (UITableView*)tableView;
- (void)maximizeForTableview: (UITableView*)tableView;
- (void)toggleForTableview: (UITableView*)tableView;

@end

@protocol AECELLSizeableDelegate <NSObject>

- (void)sizeableCellConfirmedForCell: (AECELLSizeable*)cell;
- (void)sizeableCellCancelledForCell: (AECELLSizeable*)cell;

@end

.m 文件:

#import "AECELLSizeable.h"

@implementation AECELLSizeable

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

- (void)minimizeForTableview: (UITableView*)tableView
{
    self.maximized = NO;
    [self.viewMinimized setHidden:NO];
    [self.viewMaximized setHidden:YES];
    self.height = self.viewMinimized.frame.size.height;
    [tableView beginUpdates];
    [tableView endUpdates];
}

- (void)maximizeForTableview: (UITableView*)tableView
{
    self.maximized = YES;
    [self.viewMinimized setHidden:YES];
    [self.viewMaximized setHidden:NO];
    self.height = self.viewMaximized.frame.size.height;
    [tableView beginUpdates];
    [tableView endUpdates];
}

- (void)toggleForTableview:(UITableView *)tableView
{
    if (self.maximized) {
        [self minimizeForTableview:tableView];
    } else {
        [self maximizeForTableview:tableView];
    }
}

- (void)clickedConfirm:(id)sender
{
    [self.delegate sizeableCellConfirmedForCell:self];
}

- (void)clickedCancel:(id)sender
{
    [self.delegate sizeableCellCancelledForCell:self];
}

@end

示例用法:

  1. 在 IB 中创建一个带有静态 UITableView 的 UITableViewController
  2. 将一个单元格添加到 AECELLSizeable(或其子类)的表视图中
  3. 在此单元格中创建两个 UIView。一个 UIView 将用于最小化时可见的内容,另一个将用于最大化时可见的内容。确保这些单元格在 y 轴上从 0 开始,并且它们的高度等于您希望每个状态的单元格的高度。
  4. 将任何子视图添加到您想要的这两个视图中。可以选择将确认和取消 UIButtons 添加到最大化的 UIView 并连接提供的 IBActions 以接收这些事件的委托回调。
  5. 将您的 tableview 控制器设置为符合 AECELLSizeableDelegate 并将单元格的 delegate 属性设置为 tableview 控制器。
  6. 在 UIViewController 的接口文件中为 AECELLSizeable 单元创建一个 IBOutlet。
  7. 回到 IB 中,确保单元格的初始高度是最小化版本的高度,并连接您刚刚创建的 IBOutlet。
  8. 在 tableview 控制器的实现文件中定义 tableview 的 heightForRowAtIndexPath 回调方法,如下所示:

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
      {
          if (indexPath.row == 0) {
              //Sizeable Cell
              return self.cellSizeable.height;
          } else {
              return [super tableView:tableView heightForRowAtIndexPath:indexPath];
          }
      }
    
  9. 在您的 tableview 控制器的 viewDidLoad 方法中,在您的单元格上调用 minimizeForTableview 以确保它开始最小化。

  10. 然后,在通过表格视图中的 didSelectRowAtIndexPath 回调(或者您想要处理它的其他方式)选择单元格时调用该单元格,并在您收到取消/确认的委托回调时在单元格上调用该方法单元格(或者,再一次,但是你想处理它)。
于 2013-09-10T17:06:16.953 回答
-1

看看这个库。这是使用UITableView. 请记住,每次显示单元格时,cellForRow:atIndexPath都会调用并绘制单元格。

编辑

您可以使用heightForRowAtIndexPath

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Messages *message = [self.messageList objectAtIndex:[indexPath row]];
    CGSize stringSize = [message.text sizeWithFont:[UIFont fontWithName:@"HelveticaNeue-Light" size:13]
                                    constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:UILineBreakModeWordWrap];
    return stringSize.height + 78;
}
于 2012-12-28T08:12:33.620 回答
-3

表格视图单元格不会平滑地调整大小。点。

但是,由于您的文本视图位于最后一个单元格中,因此您很幸运,因为您可以轻松模拟行大小调整。在表格中间有一个文本视图会困难得多。

我会这样做:将您的文本视图放在表格视图的顶部。将其位置与 scrollViewDidScroll: 中 tableView 的 contentOffset 同步。并使用 tableView 的动画 contentInset 以便为 textView 留出空间,因为用户在其中键入。您可能必须确保您的 textView 不可滚动。

于 2012-12-28T09:45:45.700 回答