2014-01-18 2 views
7

мне нужна небольшая помощь с NSTableView и динамической высотой строкиВид на основе NSTableView, делает высоту строки зависит от содержания

Что у меня есть:

один столбец вид на основе NSTableView, связанную с контроллер массива. Каждый NSTableCellView содержит три подзаголовка: NSImageView, NSTextField (одна строка) и NSTextField (многострочный). В принципе, это интерфейс чата, поэтому у вас будет список сообщений, отправителей и аватаров.

То, что я хочу добиться:

Если текст длиннее, чем минимальная высота строки, строка расширяется, чтобы соответствовать содержанию. Как и iMessage, пузырьки расширяются, чтобы соответствовать сообщению.

... что кажется очень естественным делом, но из всех соответствующих решений, которые я нашел в Интернете, (Ref 1, Ref 2), ни одна из которых не работает для меня.

Реф 2 выглядит фантастически написанным, но ничто из этого не применимо к моему приложению, поскольку в примере проекта используется сторонний код автомаркета, и все это предназначено для iOS. В Ref 1 дано очень многообещающее решение, написанное на английском языке. Я попытался настроить его, используя «фиктивный вид», как описано в решении, но не смог правильно изменить и измерить высоту.

Вот мой код для tableView:heightOfRow:, _samplingView - это фиктивный вид, который имеет рабочие ограничения и идентичен таковому в tableView.

- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row 
{ 
    NSTextField *textField; 
    NSTextFieldCell *messageCell; 
    for (NSView *subview in [_samplingView subviews]) { 
     if ([[subview identifier] isEqualToString:@"message"]) { 
      textField = (NSTextField*)subview; 
      messageCell = ((NSTextField*)subview).cell; 
     } 
    } 
    Message *message = [[_messagesArrayController arrangedObjects] objectAtIndex:row]; 
    _samplingView.objectValue = message; 

    CGFloat width = [[[tableView tableColumns] objectAtIndex:1] width]; 
    [_samplingView setBounds:NSMakeRect(0, 0, width, CGFLOAT_MAX)]; 
    [_samplingView display]; 

    CGFloat optimalHeight = 10 + [messageCell cellSize].height; //messageCell's size stays the same when I change samplingView to try to measure the height 
    return optimalHeight; 

} 

Результат: все высоты строк остаются такими же, как-то, когда я изменить ширину _samplingView, она не изменить размер messageCell «ы размера. Я думал, что автоматическая компоновка позаботится об этом сжатии/расширении и позволит мне измерять высоту. В самом деле, я очень смущен.

Edit: для справки, это то, что мой взгляд выглядит

 +-----------+---------------------------------------------------+ 
    |   | NSTextField          | 
    |NSImageView| sender           | 
    | avatar +---------------------------------------------------+ 
    |   |             | 
    |   | NSTextField (multiline)       | 
    +-----------| message           | 
    |   |             | 
    |   | (high compression/hugging priority)    | 
    |   | (this view should decide the height of row)  | 
    |   |             | 
    +-----------+---------------------------------------------------+ 
+0

Вы когда-нибудь находили решение этого вопроса? –

+0

@Jai, я взял удар. – stevesliva

ответ

0

Вы должны вызвать метод noteHeightOfRowsWithIndexesChanged: в Tableview, когда ширина изменяется samplingView. Этот метод упоминается в вашем «Ссылка 1.» Как сказано в документации метода:

Если делегат реализует tableView: heightOfRow: этот метод немедленно перерисовывает представление таблицы, используя высоты строк, предоставляемые делегатом.

Для таблиц на основе NSView этот метод будет анимировать. Чтобы отключить анимацию, создайте группу NSAnimationContext и установите длительность в 0. Затем вызовите этот метод и завершите группировку.

В таблице вид сверху высотой строк. Концептуально, когда вы хотите изменить высоту строки, вы должны пометить высоту как грязную, чтобы получить метод делегирования, который вы реализовали, повторно вызываемый для указанных вами строк. Нет ничего похожего на привязки какао, использующего KVO, чтобы следить за изменениями всех ключевых патчей, которые влияют на rowHeight, по крайней мере, не по умолчанию.

1

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

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

Затем не звоните -display. Вызовите -layoutSubtreeIfNeeded, а затем запросите фиктивный вид fittingSize. Высота строки должна быть высотой от fittingSize. Я не уверен, почему вы пытаетесь создать его на высоте messageCell плюс некоторое произвольное магическое число. Не обязательно иметь доступ к текстовому полю или его ячейке.

Вы говорите, что у вас есть ограничения для правильной работы ячейки. Тем не менее, вам нужно будет убедиться, что у вас есть ограничения, которые делают высоту ячейки достаточно большой, чтобы удерживать subviews. Это может быть проблемой, поскольку представление таблицы будет контролировать высоту реального (не-фиктивного) представления ячеек, и если представление таблицы временно делает его слишком коротким, чтобы удерживать подзапросы с требуемым интервалом, вы получите неудовлетворительные ограничения ошибки. Таким образом, решение состоит в том, чтобы уменьшить приоритет вертикального ограничения на дне (или высоте) представления ячеек, чтобы оно было ниже 1000 (требуется). Это может быть 250 (низкий). Он должен быть больше 50, то есть NSLayoutPriorityFittingSizeCompression. Это приоритет ограничений, которые временно использует fittingSize, чтобы попытаться сделать представление как можно меньшим.

Это должно иметь высоту, подходящую для исходного содержимого.

В качестве примечаний Ref 1 (и stevesilva) вам необходимо каким-то образом наблюдать изменения в содержании многострочного текстового поля переменной высоты. Когда он изменится, вам нужно указать в представлении таблицы, что высота строки (возможно,) изменилась, вызвав на ней -noteHeightOfRowsWithIndexesChanged:.

И, наконец, вы должны стремиться сделать как можно эффективнее -tableView:heightOfRow:. Поэтому я предлагаю вам вычислить все высоты строк при первом запросе и кешировать их. -tableView:heightOfRow: должен просто вернуть значение из кеша. Поэтому, когда вы заметили, что сообщение изменилось, вы должны вычислить новую высоту для этой строки и сравнить ее с высотой кеширования. Если и только если высота фактически изменилась - не все изменения в содержимом изменят высоту - сохраните новое значение в кеше и скажите таблице, что высота изменилась.

+0

О да, используя границы, когда вы хотите фрейм ... это убийца. Может быть, все дело. – stevesliva

Смежные вопросы