TableviewCells не вставлены, как ожидалось - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть 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];
    }
}

По сути, это вид чата, в котором я пытаюсь добиться всего хорошего, кроме этого ненормального поведения.

Я надеюсь, что кто-нибудь может потратить некоторое время и исправить меня, где я ошибаюсь.

ОБНОВЛЕНИЕ: Любой, кто ищет базовый chatView в target-C, может использовать приведенный выше код в качестве ссылки, используйтекод выше и исправьте упомянутые вещи в принятом ответе.

1 Ответ

2 голосов
/ 05 ноября 2019

Это типичная проблема повторного использования ячейки. В 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. Измените метод ваших ячеек и убедитесь, что вы обновляете свои ограничения каждый раз, когда отображается ячейка, а не только в init

Допустим, вы добавили метод с именем:

 -(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 deleteкод для установки ограничения на основе значения isReceve

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

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...