ios 有没有办法在不重新加载/重新加载行的情况下刷新单元格的高度?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14066537/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:39:07  来源:igfitidea点击:

Is there any way refresh cell's height without reload/reloadRow?

iostableview

提问by ZhouQi

I make a view like imessage, just input text into the bottom text view. I use table view to do this, and the text view in the last cell. when I input long text that more than one line, I need the text view and the cell become tailer. so I need refresh cell's height. but if I use table view's reload or reload row, the content in text view will disappear and the keyboard will disappear too. Is there any way better to fix it?

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

May be I should use tool bar to do it easy? but I still doubt table view can do it.

可能我应该使用工具栏来轻松完成?但我仍然怀疑 table view 可以做到。

回答by Matthias Bauch

The cells will resize smoothly when you call beginUpdatesand endUpdates. After those calls the tableView will send tableView:heightForRowAtIndexPath:for all the cells in the table, when the tableView got all the heights for all the cells it will animate the resizing.

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

And you can update cells without reloading them by setting the properties of the cell directly. There is no need to involve the tableView and tableView:cellForRowAtIndexPath:

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

To resize the cells you would use code similar to this

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

- (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;
}

to change the content of a cell without reloading I use something like this:

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

- (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];

回答by Adam Eisfeld

I've written a subclass of UITableViewCell to handle this functionality.

我写了一个 UITableViewCell 的子类来处理这个功能。

.h file:

.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 file:

.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

Example Usage:

示例用法:

  1. Create a UITableViewController with a static UITableView in IB
  2. Add a cell to the tableview that is a AECELLSizeable (or subclass of it)
  3. Create two UIViews in this cell. One UIView will be used for the content visible while minimized, the other will be used for the content visible while maximized. Ensure these cells start at 0 on the y axis and that their height is equal to that of the height you wish to have the cell for each state.
  4. Add any subviews to these two views you desired. Optionally add confirm and cancel UIButtons to the maximized UIView and hook up the provided IBActions to receive delegate callbacks on these events.
  5. Set your tableview controller to conform to the AECELLSizeableDelegate and set the cell's delegate property to the tableview controller.
  6. Create an IBOutlet in your UIViewController's interface file for the AECELLSizeable cell.
  7. Back in IB, ensure the cell's initial height is that of the minimized version and connect the IBOutlet you just previously created.
  8. Define the tableview's heightForRowAtIndexPath callback method in the tableview controller's implementation file as such:

    - (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. In your tableview controller's viewDidLoad method, call minimizeForTableview on your cell to ensure it starts off minimized.

  10. Then, call maximizeForTableview: on the cell when it is selected via the didSelectRowAtIndexPath callback from the tableview (or however else you would like to handle it) and call the minimizeForTableview: method on the cell when you receive the canceled / confirmed delegate callbacks from the cell (or, again, however else you'd like to handle it).
  1. 在 IB 中创建一个带有静态 UITableView 的 UITableViewController
  2. 将单元格添加到 AECELLSizeable(或其子类)的表格视图中
  3. 在此单元格中创建两个 UIView。一个 UIView 将用于最小化时可见的内容,另一个将用于最大化时可见的内容。确保这些单元格在 y 轴上从 0 开始,并且它们的高度等于您希望每个状态的单元格的高度。
  4. 将任何子视图添加到您想要的这两个视图中。可选地将确认和取消 UIButtons 添加到最大化的 UIView 并连接提供的 IBActions 以接收这些事件的委托回调。
  5. 将您的 tableview 控制器设置为符合 AECELLSizeableDelegate 并将单元格的委托属性设置为 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 方法中,在您的单元格上调用 minimumForTableview 以确保它从最小化开始。

  10. 然后,在通过来自 tableview 的 didSelectRowAtIndexPath 回调(或您想处理它的其他方式)选择单元格时调用 maximizeForTableview: 并在收到来自单元格(或者,再一次,不管你想处理它)。

回答by amb

Check out this library. This is an implementation of message bubbles using UITableView. Keep in mind that every time a cell is displayed, cellForRow:atIndexPathis called and the cell is drawed.

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

EDIT

编辑

You can use heightForRowAtIndexPath

您可以使用 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;
}

回答by Gwendal Roué

Table view cells won't smoothly resize. Dot.

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

However, since your text view is in the last cell, you are lucky because you can easily simulate a row resizing. Having a text view in the middle of the table would be much more difficult.

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

Here is how I would do it: put your text view on top of the table view. Sync its position with the contentOffset of the tableView in scrollViewDidScroll:. And use the animatable contentInset of the tableView in order to leave room for the textView, as the user types in it. You may have to make sure your textView is not scrollable.

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