未按预期插入TableviewCells

我有一个reusabletablViewCell,只要用户在教科书中输入内容并单击“发送”按钮,它就会被简单地回显到表格视图中,我的问题是单元格的行为与预期的不同,几次是正确插入单元格,几次是他们不会。

预期的行为:当用户在文本框中键入一些文本后单击“发送”按钮时,应将相同的值打印两次(例如发送和接收相同的文本)。

//view somewhat looks like this on expected behaviour

         '''''''''
         '  hi   '
         '''''''''
'''''''''
'  hi   '
'''''''''

当前行为:有时确实可以给我预期的行为,但有时两个单元格都在同一侧

EX:

//view when it doesn't work as expected

          ''''''' 
          ' hi  '
          '''''''

          '''''''
          ' hi  '
          '''''''

or something like 

''''''''
'  hi  '
''''''''

''''''''
'  hi  '
''''''''

有时,当我们滚动时,单元会从发送者到接收者改变它们的位置(在代码中可以看到的是奇数单元格和偶数单元格,反之亦然)。

我的代码

//FirstTableViewController.h


#import <UIKit/UIKit.h>
@class SecondViewController;
@interface FirstTableViewController : UITableViewController
@property (strong,nonatomic) IBOutlet UITableView *messageView;
@property (nonatomic,readwrite) NSInteger counter;
@property (nonatomic,readwrite) NSMutableArray *userInput;
@property (nonatomic,readwrite) NSMutableDictionary *heightAtIndexPath;
@property (nonatomic,assign) BOOL shouldScrollToLastRow;
+ (id)sharedInstance;
@end
@interface ChatMessageCellTableViewCell : UITableViewCell
@property (nonatomic,retain) UILabel *formLabel;
@property (nonatomic,retain) UIView *bubbleBackView;
@end

//FirstTableViewController.m

#import "FirstTableViewController.h"
BOOL isReceived;
@interface ChatMessageCellTableViewCell (){
    NSLayoutConstraint *leadingConstraint;
    NSLayoutConstraint *trailingConstraint;
}
@end

@implementation ChatMessageCellTableViewCell
-(void) loaded{
    if(isReceived){
        [self.bubbleBackView setBackgroundColor:[UIColor whiteColor]];
        [self.formLabel setTextColor:[UIColor blackColor]];

    }
    else{
        [[self bubbleBackView] setBackgroundColor:[UIColor colorWithRed:(66/255) green:(137/255.0)  blue:1  alpha:1.0]];
        [self.formLabel setTextColor:[UIColor whiteColor]];
    }
}
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    [self setBackgroundColor:[UIColor clearColor]];
    self.formLabel = [UILabel new];
    self.bubbleBackView = [UIView new];

    //[self.bubbleBackView setBackgroundColor:[UIColor yellowColor]];
    [self.bubbleBackView.layer setCornerRadius:12];
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if(self){
        [[self contentView] addSubview:self.bubbleBackView
         ];
        [self loaded];
        [self.bubbleBackView setTranslatesAutoresizingMaskintoConstraints:NO];
        [[self contentView] addSubview:self.formLabel];

        [self.formLabel setTranslatesAutoresizingMaskintoConstraints:NO];
        if (@available(iOS 9.0,*)) {
            [self.formLabel.topAnchor constraintEqualToAnchor:self.topAnchor constant:32].active=YES;
            [self.formLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-32].active=YES;
            [self.formLabel.widthAnchor constraintLessThanOrEqualToConstant:250].active=YES;

            [self.bubbleBackView.topAnchor constraintEqualToAnchor:_formLabel.topAnchor constant:-16].active=YES;
            [self.bubbleBackView.bottomAnchor constraintEqualToAnchor:_formLabel.bottomAnchor constant:16].active=YES;
            [self.bubbleBackView.trailingAnchor constraintEqualToAnchor:_formLabel.trailingAnchor constant:16].active=YES;
            [self.bubbleBackView.leadingAnchor constraintEqualToAnchor:_formLabel.leadingAnchor constant:-16].active=YES;
            leadingConstraint= [self.formLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:32];
            trailingConstraint = [self.formLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-32];
            if(isReceived){
                [leadingConstraint setactive:YES];
                [trailingConstraint setactive:NO];
            }
            else{
                [leadingConstraint setactive:NO];
                [trailingConstraint setactive:YES];
            }
        } else {
            // Fallback on earlier versions
        }
        [self.formLabel setLineBreakMode:NSLineBreakByWordWrapping];
        [self.formLabel setNumberOfLines:0];
        [self.formLabel sizeToFit];
        [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-40-[bodyLabel]-40-|" options:0
                                                                                 metrics:nil
                                                                                   views:@{ @"bodyLabel":self.formLabel}]];

    }
    return self;
}
@end
@interface FirstTableViewController ()
{
    NSArray *messages;
    FirstTableViewController *classA;
}
@end

@implementation FirstTableViewController
+(id)sharedInstance
{
    static FirstTableViewController *sharedClassA = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        sharedClassA = [[self alloc] init];
    });
    return sharedClassA;
}
- (void)viewDidLoad {
    [super viewDidLoad];
     self.heightAtIndexPath = [NSMutableDictionary new];
    self.userInput = [[NSMutableArray alloc] init];
    [self.tableView registerClass:[ChatMessageCellTableViewCell class] forCellReuseIdentifier:@"id"];
    [[self tableView] setSeparatorStyle:UITableViewCellSeparatorStyleNone];
    [self.tableView setBackgroundColor:[UIColor colorWithWhite:0.95 alpha:1]];
    [[self navigationController] setTitle:@"Meetings"];
     classA = [FirstTableViewController sharedInstance];
    [classA setCounter:(classA.userInput.count)];
    [classA setMessageView:(self.messageView)];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    classA.counter=classA.userInput.count;
    return classA.counter;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellIdentifier = (indexPath.row % 2 == 0 ? @"EvenCell" : @"OddCell"); //just to differentiate the sending and receiving cell.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    ChatMessageCellTableViewCell *messageCell = (ChatMessageCellTableViewCell*) cell;
    if (messageCell == nil) {
        messageCell = [[ChatMessageCellTableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
            reuseIdentifier:cellIdentifier];
    }
    if(indexPath.row % 2 == 0) // simple logic to differentiate and apply my constraints to the sending and receiving cells.
    {
        isReceived =TRUE;
    }
    else{
        isReceived = FALSE;
    }
    [[messageCell formLabel]setText:classA.userInput[indexPath.row]];
    [messageCell setSelectionStyle:UITableViewCellSelectionStyleNone];
    [[self tableView] setEstimatedRowHeight:50.0];
    [self.tableView setRowHeight:UITableViewAutomaticDimension];
    return messageCell;
}

-(void)viewWillLayoutSubviews{
    if(classA.shouldScrollToLastRow){
        [classA setShouldScrollToLastRow:NO];
        dispatch_async(dispatch_get_main_queue(),^{
            NSIndexPath *path = [NSIndexPath indexPathForRow:(self->classA.counter)-1 inSection:0];
            //Basically maintain your logic to get the indexpath
            [self->classA.messageView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionBottom animated:NO];
        });
    }

}

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

}
-(void)dealloc{
    NSLog(@"Dealloc!!!");
}
@end

//SecondViewController.m

//sendButtonClicked is the function from where the data is passed to the FirstViewController's tableview cell.
-(IBaction)sendButtonClicked{
    NSString *input = self.ChatTextInput.text;
    if([input isEqualToString:@""]){
        NSLog(@"this is a nil ");
    }
    else{
        [inputvalues addObject:input];
        [inputvalues addObject:input];
        [classA setUserInput:inputvalues];
        [classA setCounter:inputvalues.count];
        [self.ChatTextInput setText:nil];
        [classA setShouldScrollToLastRow:YES];
        [classA.messageView reloadData];
    }
}

这基本上是一个聊天视图,我实际上试图实现除此异常行为以外的所有功能。

我希望任何人都可以花些时间纠正我在哪里错了。

更新:在Objective-C中寻找基本chatView的任何人都可以使用上面的代码作为参考,使用上面的代码并更正可接受的答案中提到的内容。

lisagaga111 回答:未按预期插入TableviewCells

这是一个典型的单元重用问题。在iOS中,所有集合(UITableView / UICollectionView)都重复使用单元格,并且仅在初始化单元格后才调用单元格initWithStyle。一旦tableView有足够的单元格,它将重用该单元格,因此initWithStyle不会一直被调用。因此,您的所有单元格(最好是初始单元格)看起来都不错。由于您在init中正确设置了其约束,而对于未正确显示的其他单元格,init从未被调用过,因此您的约束也从未更新。因此显示错误的气泡。

解决方案是什么?:

1。使用PrepareforReuse 每个单元重用时,iOS都会在该单元上调用prepareForReuse,为开发人员提供最后一次清理工作的机会

-(void) prepareForReuse {
    [super prepareForReuse];
    [self.formLabel setText: nil];
    //set default background color or change bubble view
    // do whatever clean up you wanna do here
}

2。修改单元格方法,确保每次显示单元格时都更新约束,而不仅仅是在初始化时

让我们说您添加了一个称为:

的方法
 -(void)configureView:(BOOL) isRecieved {
    isReceived = isRecieved;
    if(isReceived){
        [leadingConstraint setActive:YES];
        [trailingConstraint setActive:NO];
    }
    else{
        [leadingConstraint setActive:NO];
        [trailingConstraint setActive:YES];
    }
    //[self layoutIfNeeded]; might be needed here
    [self loaded];

}

在您的init中,删除代码以基于isRecieved值设置约束

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    [self setBackgroundColor:[UIColor clearColor]];
    self.formLabel = [UILabel new];
    self.bubbleBackView = [UIView new];

    //[self.bubbleBackView setBackgroundColor:[UIColor yellowColor]];
    [self.bubbleBackView.layer setCornerRadius:12];
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if(self){
        [[self contentView] addSubview:self.bubbleBackView
         ];
        [self loaded];
        [self.bubbleBackView setTranslatesAutoresizingMaskIntoConstraints:NO];
        [[self contentView] addSubview:self.formLabel];

        [self.formLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
        if (@available(iOS 9.0,*)) {
            [self.formLabel.topAnchor constraintEqualToAnchor:self.topAnchor constant:32].active=YES;
            [self.formLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-32].active=YES;
            [self.formLabel.widthAnchor constraintLessThanOrEqualToConstant:250].active=YES;

            [self.bubbleBackView.topAnchor constraintEqualToAnchor:_formLabel.topAnchor constant:-16].active=YES;
            [self.bubbleBackView.bottomAnchor constraintEqualToAnchor:_formLabel.bottomAnchor constant:16].active=YES;
            [self.bubbleBackView.trailingAnchor constraintEqualToAnchor:_formLabel.trailingAnchor constant:16].active=YES;
            [self.bubbleBackView.leadingAnchor constraintEqualToAnchor:_formLabel.leadingAnchor constant:-16].active=YES;
            leadingConstraint= [self.formLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:32];
            trailingConstraint = [self.formLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-32];

        } else {
            // Fallback on earlier versions
        }
        [self.formLabel setLineBreakMode:NSLineBreakByWordWrapping];
        [self.formLabel setNumberOfLines:0];
        [self.formLabel sizeToFit];
        [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-40-[bodyLabel]-40-|" options:0
                                                                                 metrics:nil
                                                                                   views:@{ @"bodyLabel":self.formLabel}]];

    }
    return self;
}

最后,在cellForRowAtIndexPath中,调用configureView值为isReceived

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellIdentifier = (indexPath.row % 2 == 0 ? @"EvenCell" : @"OddCell"); //just to differentiate the sending and receiving cell.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    ChatMessageCellTableViewCell *messageCell = (ChatMessageCellTableViewCell*) cell;
    if (messageCell == nil) {
        messageCell = [[ChatMessageCellTableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
            reuseIdentifier:cellIdentifier];
    }
    if(indexPath.row % 2 == 0) // simple logic to differentiate and apply my constraints to the sending and receiving cells.
    {
        isReceived =TRUE;
    }
    else{
        isReceived = FALSE;
    }
    [messageCell configureView: isReceived];
    [[messageCell formLabel]setText:classA.userInput[indexPath.row]];
    [messageCell setSelectionStyle:UITableViewCellSelectionStyleNone];
    [[self tableView] setEstimatedRowHeight:50.0];
    [self.tableView setRowHeight:UITableViewAutomaticDimension];
    return messageCell;
}

希望有帮助

本文链接:https://www.f2er.com/3162051.html

大家都在问