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

前端 未结 4 1074
忘掉有多难
忘掉有多难 2021-01-31 09:41

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 on

相关标签:
4条回答
  • 2021-01-31 10:08

    The cells will resize smoothly when you call beginUpdates and 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.

    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:

    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];
    
    0 讨论(0)
  • 2021-01-31 10:09

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

    .h file:

    #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:

    #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).
    0 讨论(0)
  • 2021-01-31 10:20

    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.

    0 讨论(0)
  • 2021-01-31 10:30

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

    EDIT

    You can use 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;
    }
    
    0 讨论(0)
提交回复
热议问题