UITableViewCell с изображениями разных размеров

Я пытаюсь использовать свой ReusableCell для ячеек с изображениями разных размеров. Изображения помещаются в черный квадрат 220x150 с масштабированием UIViewContentModeScaleAspectFit.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"NewsTableViewCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    NewsItem *item = [self.fetchedResultsController objectAtIndexPath:indexPath];

    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:item.imageUrl]];
    [cell.imageView setImage:[[UIImage alloc] initWithData:data]];
    [cell.imageView setBackgroundColor:[UIColor blackColor]];
    [cell.imageView setContentMode:UIViewContentModeScaleAspectFit];

    CGRect imageViewFrame = cell.imageView.frame;
    imageViewFrame.size.width = 220;
    imageViewFrame.size.height = 150
    [cell.imageView setFrame:imageViewFrame];

    [cell.textLabel setText:item.title];

    return cell;
}

Приведенный выше код приводит к следующему макету, и изображения иногда меняются при прокрутке в виде таблицы.

UITableView with images

Вместо этого неструктурированного макета я хотел бы, чтобы изображения были выровнены следующим образом:

Images in a black box

Что я делаю неправильно с этим ReusableCell?

EDIT1:

Я пытаюсь создать imageView и добавить этот образView как супервизор в cell.contentView.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"NewsTableViewCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    NewsItem *item = [self.fetchedResultsController objectAtIndexPath:indexPath];

    UIImage *placeholderImage = [UIImage imageNamed:@"ImagePlaceholderThumb"]; //220x150

    UIImageView *imageView = [[UIImageView alloc] initWithImage:placeholderImage];

    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:item.imageUrl]];
    [imageView setImage:[[UIImage alloc] initWithData:data]];
    [imageView setBackgroundColor:[UIColor blackColor]];
    [imageView setContentMode:UIViewContentModeScaleAspectFit];

    CGRect imageViewFrame = imageView.frame;
    imageViewFrame.size.width = placeholderImage.size.width;
    imageViewFrame.size.height = placeholderImage.size.height;
    [imageView setFrame:imageViewFrame];

    [cell.contentView addSubview:imageView];

    [cell.textLabel setText:item.title];

    return cell;
}

Приведенный выше код приводит к следующему:

UIImageView in superview

Это похоже на то, что некоторые изображения видны в двух ячейках. Кажется, что они не поддерживают размер, который я установил в imageViewFrame. Вы знаете, почему?

Ответ 1

Быстрое исправление будет использовать режим содержимого UIViewContentModeScaleAspectFill. Изображения будут растянуты в одном или обоих измерениях, чтобы заполнить границы всего изображения.

Вам действительно нужно выполнить подкласс UITableViewCell, чтобы сделать это правильно.

Thre - это ленивое решение, добавляющее новый UIImageView и использование спейсера, как сказал Келлер в своем ответе (не стесняйтесь принять его ответ, это всего лишь недостающий код).

Выдержка tableView:cellForRowAtIndexPath::

...
cell.textLabel.text = [NSString stringWithFormat:@"Cell #%i", indexPath.row];
cell.imageView.image = [UIImage imageNamed:@"spacer.png"]; /* spacer is 64 x 44 */
/* image view width should be ~ 64 px, otherwise it will overlap the text */
UIImageView *iv = [[UIImageView alloc] initWithFrame:(CGRect){.size={64, tableView.rowHeight}}];
switch (indexPath.row) {
    case 0:
        iv.image = [UIImage imageNamed:@"waterfall.png"];
        break;
    /* etc... */
}
if (indexPath.row < 3) {
    /* add black bg to cell w/ images */
    iv.backgroundColor = [UIColor blackColor];
}
iv.contentMode =  UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:iv];
...

Таблица будет выглядеть так: aspect fit

Вам нужно установить заполнитель (spacer.png выше) в существующем виде изображения ячейки. Он нажимает текстовую метку справа.

Вы можете использовать аспект заполнения и удалить бит цвета фона:

iv.contentMode =  UIViewContentModeScaleAspectFill;

Таблица будет выглядеть неправильно, потому что изображение вычерчивается за пределы границ:

aspect fill without clipping

Просто клип, чтобы получить лучший результат:

iv.clipsToBounds = YES;

aspect fill

Ответ 2

Создайте подпрограмму UIImageView для каждой ячейки и ее в contentView. Каждый UIImageView содержит изображение с согласованным фреймом, но с опцией UIViewContentModeScaleAspectFit. Затем просто установите цвет фона UIImageView в черный.

Я только что подтвердил это, но вам нужно также создать образ spacer spacer, чтобы убедиться, что textLabel уходит с пути. Просто сделайте одинаковые размеры вашего изображения (с бокс-письмом).

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *CellIdentifier = @"Cell";

  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

    //spacer
    cell.imageView.image = [UIImage imageNamed:@"placeholder"];

    //imageview
    UIImageView *thumbnail = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 80, 44)];
    thumbnail.tag = kThumbTag;
    thumbnail.backgroundColor = [UIColor blackColor];
    thumbnail.contentMode = UIViewContentModeScaleAspectFit;
    [cell.contentView addSubview:thumbnail];
  }

  // Configure the cell...

  cell.textLabel.text = [NSString stringWithFormat:@"Cell %d", indexPath.row];

  cell.imageView.frame = CGRectMake(0, 0, 80, 44);

  UIImageView *thumb = (UIImageView*)[cell.contentView viewWithTag:kThumbTag];
  if (indexPath.row == 0) {
    [thumb setImage:[UIImage imageNamed:@"image1.png"]];
  } else {
    [thumb setImage:[UIImage imageNamed:@"image2.png"]];
  }

  return cell;
}

Очевидно, что этот пример - это не ленивая загрузка изображений (я не понимал, что вы загружаете их из URL-адреса). Для этого я бы использовал подкласс с EGOImageView или что-то подобное.