UITableView имеет уродливое фоновое изображение для строк с динамической высотой

Я создал UITableViewController, который вычисляет высоту каждой строки в зависимости от количества содержащегося в ней текста. Код для вычисления высоты строки выглядит так:

- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
    Message *message = [[[[SessionData sharedSessionData] sessions] objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
    CGSize size = [[message text] sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

    return size.height + (CELL_CONTENT_MARGIN * 2) + 38;
}

Как вы могли заметить, я использую отдельный класс в качестве UITableViewDatasource, который называется SessionData. Внутри класса SessionData я рисую строки. Каждая строка имеет верхнее изображение, центральное изображение (которое повторяется в зависимости от высоты строки) и нижнее изображение. Моя проблема заключается в следующем: центральное изображение рисуется немного темнее, чем нижнее и верхнее изображения. Я предполагаю, что это как-то связано с повторяющимся характером изображения, так как верхнее и нижнее изображения нарисованы нормально. Следующий код является частью моего сообщения [tableView:cellForRowAtIndexPath:]:

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

    // other stuff here, most likely not related to my issue ...

    Message *message  = [[sessions objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];       
    CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
    CGSize size = [[message text] sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

    [label setText:[message text]];
    [label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN - 5.0f, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), size.height)];
    [label setBackgroundColor:[UIColor clearColor]];

    viewTop = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"im1 top.png"]];
    viewMid = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"im1 mid.png"]];
    viewBot = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"im1 bot.png"]];      

    [viewTop setFrame:CGRectMake(0.0, 0.0, 300.0, 17.0)];
    [viewMid setFrame:CGRectMake(0.0, 17.0, 300.0, size.height - 10)];
    [viewBot setFrame:CGRectMake(0.0, 17.0 + size.height - 10, 300.0, 31.0)];

    [viewTop setBackgroundColor:[UIColor clearColor]];
    [viewMid setBackgroundColor:[UIColor clearColor]];
    [viewBot setBackgroundColor:[UIColor clearColor]];  

    [cell.backgroundView setBackgroundColor:[UIColor clearColor]];

    [((UIImageView *)cell.backgroundView) addSubview:viewTop];  
    [((UIImageView *)cell.backgroundView) addSubview:viewMid];  
    [((UIImageView *)cell.backgroundView) addSubview:viewBot];

    [[cell backgroundView] addSubview:label];   

    return cell;
}

Я предполагаю, что мне нужно будет создать containerView с общим размером (шириной, высотой) для верхнего, центрального и нижнего изображений и добавить containerView в ячейку, но это, похоже, не сработало. Кто-нибудь знает, как решить эту проблему?

ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ: мой UITableViewController имеет градиент в качестве фонового изображения. Таким образом, верхнее/центральное/нижнее изображения рисуются поверх фонового градиента. Возможно, это тоже часть проблемы.


person Wolfgang Schreurs    schedule 18.01.2010    source источник


Ответы (2)


Несколько вещей, на которые следует обратить внимание.

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

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        // Do cell layout in here!
    }

Таким образом, ячейки и их подпредставления можно использовать повторно, а не создавать заново каждый раз, когда ячейка появляется на экране (используйте tag свойства и viewWithTag: методы представлений).

Во-вторых, вы можете посмотреть растягиваемые изображения.

В-третьих, вы заметите гораздо лучшую производительность, рисуя ячейки вручную. Создайте собственное представление (которое вы добавляете в представление содержимого), переопределите drawRect:, нарисуйте на них изображения, используя метод drawInRect: UIImage. Это значительно ускорит работу! Нарисуйте все, что можете, потому что раскладка subview — это дорого! Кроме того, убедитесь, что вы не используете прозрачность UIView (включая UIImageView, UILabel и т. д.), если это возможно, установите opaque = YES и установите цвета фона. Предпочтительно рисовать текст в drawRect:, используя метод drawInRect: NSString, который придаст вид прозрачной UILabel.

Однако, если у вас ОЧЕНЬ мало ячеек, например, ‹ 4 или что-то в этом роде, то, возможно, метод рисования — это слишком много. Тем не менее, это все еще очень рекомендуется!

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

person Michael Waterfall    schedule 18.01.2010

Спасибо за ваши предложения Михаил. Я действительно мог исправить свои проблемы с графикой, используя следующий код:

[bubbleView setImage:[bubble stretchableImageWithLeftCapWidth:165 topCapHeight:30]];

Вместо того, чтобы использовать 3 отдельных изображения для создания пузырей чата, теперь я могу использовать 1 изображение, и оно изящно растягивается. Действительно, очень хорошее предложение :)

Несмотря на то, что у меня не было особых проблем со скоростью, я частично переписал свой код, как вы предложили, в основном путем создания основной части ячеек в части кода, инициализирующей ячейки. Я заметил небольшое улучшение скорости, возможно, оно более заметно на устройстве (по сравнению с симулятором).

В настоящее время я все еще рисую свои изображения с помощью ImageView (как вы могли заметить), я буду смотреть на [UIImage drawInRect:] всякий раз, когда мне нужно больше скорости рендеринга.

Спасибо за ваши предложения, очень ценится.

person Wolfgang Schreurs    schedule 18.01.2010
comment
Добро пожаловать! Да, я бы посоветовал регулярно тестировать на устройстве. Симулятор работает очень быстро, так как использует всю память и мощность процессора вашего Mac. Если у вас есть достаточное количество строк, я думаю, вы увидите медленную частоту кадров при прокрутке на устройстве (по сравнению, скажем, с приложением для обмена текстовыми сообщениями или приложением для iPod). Сначала я тратил много времени только на симулятор, а когда в конце концов протестировал на устройстве, все было чрезвычайно медленным, и мне пришлось переписать весь код табличного представления! (при условии, что я их активно использовал!) Но я усвоил урок! Удачи! - person Michael Waterfall; 18.01.2010