UILabel добавляется несколько раз на UITableViewCell

90
5

У меня есть UITableViewCell, который отображает данные из массива JSON, состоящего из изображений Instagram. Однако UITableViewCell перепутано в том смысле, что каждая соответствующая ячейка имеет предыдущие данные Cells поверх нее. Это скорее проблема пользовательского интерфейса, а не проблема веб-API. Эта проблема может быть лучше всего показана на картинке, поэтому я привел ее ниже enter image description here. Вот код, который я использую:

   UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"InstaCell"];
cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Background.png"]];

if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"InstaCell"];
}

NSDictionary *entry = instaPics[indexPath.row];

//
// SETUP VIEWS
//

// Name
self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(73, 6, 192, 25)];
[self.nameLabel setFont:[UIFont fontWithName:@"Helvetica-Regular" size:16.0]];

// Profile Pic
self.profilePic = [[UIImageView alloc] initWithFrame:CGRectMake(10, 6, 50, 50)];

// Date Label
self.dateLabel = [[UILabel alloc] initWithFrame:CGRectMake(68, 29, 192, 21)];
[self.dateLabel setFont:[UIFont fontWithName:@"Helvetica-Light" size:12.0]];

// Like Button
self.likeButton = [[UIButton alloc] initWithFrame:CGRectMake(68, 279, 18, 18)];
[self.likeButton setBackgroundImage:[UIImage imageNamed:@"heartShape.png"] forState:UIControlStateNormal];
[self.likeButton addTarget:self action:@selector(didTapLikeButton:) forControlEvents:UIControlEventTouchUpInside];

// Comment Button
self.commentButton = [[UIButton alloc] initWithFrame:CGRectMake(68, 29, 192, 21)];

// Like Label
self.likeLabel = [[UILabel alloc] initWithFrame:CGRectMake(40, 371, 50, 21)];
self.likeLabel.font = [UIFont fontWithName:@"HelveticaNeue-Medium" size:14];
self.likeLabel.textColor = [UIColor orangeColor];

// Heart Icon
self.heartIcon = [[UIButton alloc] initWithFrame:CGRectMake(20, 375, 14, 14)];
[self.heartIcon setBackgroundImage:[UIImage imageNamed:@"heart.png"] forState:UIControlStateNormal];
[self.heartIcon setTitleColor:[UIColor grayColor]
forState:UIControlStateHighlighted];
[self.heartIcon addTarget:self action:@selector(didTapLikeIcon:) forControlEvents:UIControlEventTouchUpInside];

// Comment Icon
self.commentIcon = [[UIButton alloc] initWithFrame:CGRectMake(20, 395, 14, 14)];
[self.commentIcon setBackgroundImage:[UIImage imageNamed:@"comment.png"] forState:UIControlStateNormal];
[self.commentIcon setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
[self.commentIcon addTarget:self action:@selector(didTapCommentIcon:) forControlEvents:UIControlEventTouchUpInside];

// Comment Text
self.commentText = [[UILabel alloc] initWithFrame:CGRectMake(-88, 370, 259, 40)];
[[self.commentText layer] setAnchorPoint:CGPointMake(0, 0)];
self.commentText.font = [UIFont fontWithName:@"HelveticaNeue" size:14];
self.commentText.lineBreakMode = NSLineBreakByWordWrapping;
self.commentText.numberOfLines = 3;
self.commentText.textColor = [UIColor blackColor];

// Location Icon
self.locationIcon = [[UIButton alloc] initWithFrame:CGRectMake(73, 33, 12, 12)];
[self.locationIcon setBackgroundImage:[UIImage imageNamed:@"location.png"] forState:UIControlStateNormal];
[self.locationIcon setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
[self.locationIcon addTarget:self action:@selector(didTapLocationIcon:) forControlEvents:UIControlEventTouchUpInside];

// Heart Button
self.heartButton = [[UIButton alloc] initWithFrame:CGRectMake(40, 465, 25, 25)];
[self.heartButton setBackgroundImage:[UIImage imageNamed:@"heart.png"] forState:UIControlStateNormal];
[self.heartButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];

// Comment Button
self.commentButton = [[UIButton alloc] initWithFrame:CGRectMake(220, 465, 25, 25 )];
[self.commentButton setBackgroundImage:[UIImage imageNamed:@"comment.png"] forState:UIControlStateNormal];
[self.commentButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];

//
// ADD DATA
//

// Set User Name
NSString *user = entry[@"user"][@"full_name"];
[self.nameLabel setText:user];

// If no Caption
if (entry[@"caption"] != [NSNull null] && entry[@"caption"][@"text"] != [NSNull null]) {
NSString *caption = entry[@"caption"][@"text"];
[self.commentText setText:caption];
}else{
NSString *caption = @"";
[self.commentText setText:caption];
}

// Set the number of likes
NSString *likesCount = entry[@"likes"][@"count"];
NSString *likes = [NSString stringWithFormat: @"%@", likesCount];
[self.likeLabel setText:likes];

// Add Profile Image
NSURL *imageUrl = entry[@"user"][@"profile_picture"];
[self.profilePic sd_setImageWithURL:imageUrl completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
self.profilePic.image = image;
//Make the Profile Pic ImageView Circular
CALayer *imageLayer = self.profilePic.layer;
[imageLayer setCornerRadius:25];
[imageLayer setMasksToBounds:YES];
}];

//NSString *latitude = entry[@"location"][@"latitude"];
//NSString *longitude = entry[@"location"][@"longitude"];

//if ([[entry objectForKey:@"location"] objectForKey:@"latitude"] == NSNotFound) {
// NSLog(@"Contains Location");
//}

[self.commentButton addTarget:self action:@selector(commentButtonTap:) forControlEvents:UIControlEventTouchUpInside];
[self.likeButton addTarget:self action:@selector(likeButtonTap:) forControlEvents:UIControlEventTouchUpInside];

NSDictionary *instapic = [self.instaPics objectAtIndex:indexPath.row];

// Comparator to determine if their are any videos availible
if (entry[@"videos"] != nil) {
// Set Videos
NSLog(@"there are videos: %@", entry[@"videos"]);
CGFloat width = [UIScreen mainScreen].bounds.size.width;
_playerView = [[GUIPlayerView alloc] initWithFrame:CGRectMake(10, 65, 299, 299)];
[_playerView setDelegate:self];

[[self view] addSubview:_playerView];

NSString *urlstring = entry[@"videos"][@"standard_resolution"][@"url"];

NSURL *URL = [NSURL URLWithString:urlstring];
[_playerView setVideoURL:URL];
[_playerView prepareAndPlayAutomatically:YES];
}else{
// Set Image
self.instagramPic = [[UIImageView alloc] initWithFrame:CGRectMake(10, 65, 299, 299)];
NSString *imageUrlString = entry[@"images"][@"low_resolution"][@"url"];
NSURL *url = [NSURL URLWithString:imageUrlString];
[self.instagramPic sd_setImageWithURL:url];

}

//
// ADD ALL SUBVIEWS
//

[cell addSubview:self.commentButton];
[cell addSubview:self.nameLabel];
[cell addSubview:self.profilePic];
[cell addSubview:self.instagramPic];
[cell addSubview:self.dateLabel];
[cell addSubview:self.likeButton];
[cell addSubview:self.commentButton];
[cell addSubview:self.likeLabel];
[cell addSubview:self.heartIcon];
[cell addSubview:self.commentIcon];
[cell addSubview:self.commentText];
[cell addSubview:self.locationIcon];
[cell addSubview:self.heartButton];

return cell;

спросил(а) 2015-04-27T01:00:00+03:00 5 лет, 6 месяцев назад
1
Решение
58

Вы добавляете метки в представление снова каждый раз при загрузке фрейма. метод cellForRowAtIndexPath: это неправильное место для добавления настраиваемых полей в ячейку.

Вам нужно создать пользовательский подкласс UITableViewCell и добавить туда поля и выставить их через свойства или методы и просто установить новые значения в cellForRowAtIndexPath:

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

ответил(а) 2015-04-27T01:06:00+03:00 5 лет, 6 месяцев назад
59

Вы действительно должны подклассифицировать UITableViewCell вместо создания представлений внутри самой ячейки.

Однако, если вы действительно не хотите подкласса (подклассификация замечательна). Создание объектов внутри метода создания ячейки


    if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"InstaCell"];
UIButton *button = // etc...

}

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

ответил(а) 2015-04-27T02:00:00+03:00 5 лет, 6 месяцев назад
58

Когда вы вызываете dequeueReusableCellWithIdentifier вам может быть предоставлена ячейка, которая уже была отображена в другом месте в вашей таблице, а затем прокручена. То, что "многоразовое" означает для клеток.

Вы можете либо создать файл.xib, который содержит вашу пользовательскую ячейку со всеми ее представлениями, так и просто установить данные в вашем методе, или вы можете реализовать prepareForReuse для удаления добавленных видов.

ответил(а) 2015-04-27T01:07:00+03:00 5 лет, 6 месяцев назад
41

Используя dequeueReusableCellWithIdentifier UITableViewDataSource protocol будет повторно использовать ячейки, поэтому вы добавляете представления к ячейкам, которые вы уже добавили ранее.

Возможно, это не самое лучшее, но самое простое решение - удалить уже добавленные subView, прежде чем добавлять новые.

перед добавлением subviews попробуйте следующее:

for (UIView *subView in cell.contentView.subviews) {
[subView removeFromSuperview];
}

Еще одна вещь, вы должны добавить subview в cell.contentView

РЕДАКТИРОВАТЬ

Как комментарий Тима:

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

РЕДАКТИРОВАТЬ

Лучшее решение - создать пользовательский UITableViewCell

YourCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YourCellIdentifier"];
if (!cell) {
cell = [[YourCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"YourCellIdentifier"];
}

Затем вы можете создать Xib и подключить IBOutlet.

Затем, например, если вы создаете розетку для nameLabel, вы можете сделать что-то вроде этого:

[cell.nameLabel setText:entry[@"user"][@"full_name"]];

ответил(а) 2015-04-27T01:57:00+03:00 5 лет, 6 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема