Лучший подход для UITableViewCell со сложным форматом

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

Sketch

Каждый элемент включает миниатюру, заголовок, рекламный блок и набор кнопок. Есть два осложнения:

  • Количество текста и количество кнопок являются переменными.
  • Текст требует некоторого внутреннего форматирования (курсив и полужирный).

Я рассмотрел эти подходы:

  • Используйте представление таблицы с настраиваемым, изменяемым по размеру UITableViewCell, возможно, используя для этого текст, например, OHAttributedLabel. Для переменного количества кнопок либо выкладывайте их программно, либо, возможно, используйте новый вид коллекции (для более старых iOS, необходимо использовать стороннее представление сетки).

  • Используйте представление таблицы с пользовательской ячейкой на основе UIWebView.

  • Сделайте весь набор как один UIWebView.

  • Используйте представление таблицы с разделами; каждый элемент имеет свой собственный раздел и разбирает кнопки и текст в строках.

Хотелось бы получить предложения о том, как к этому приблизится более опытный разработчик iOS.

EDIT: теперь я считаю, что лучший способ может быть:

5) Используйте UICollectionView для всего этого.

UPDATE: В конце концов, я заложил все это в код как пользовательскую ячейку таблицы (например, # 1). Это был хороший выбор не только по причинам, указанным в ответе, но и потому, что, как кто-то новый для разработки iOS, мне нужно было получить под моим поясом. Даже не использовал представление коллекции для кнопок, потому что меня беспокоило производительность, а также хлопот поддержки iOS5.

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

2nd UPDATE: # 1 оказался тупиком. Мое окончательное решение использовало UIWebView (# 3) - см. Ответ.

Ответ 1

Я изначально принял (и реализовал) @Daij-Djan ответ, но теперь я считаю, что лучший подход - это № 3 (UIWebView). Это сводится к производительности.

Установки UITableView хорошо работают с настраиваемыми ячейками с subviews, особенно в контексте ячеек с разной высотой. Строки кнопок делают прокрутку изменчивой. Как явствует из Apple в Cells and Table View Performance, я убедился, что subviews все непрозрачны, однако нет способа следовать предложению" Избегайте ретрансляции содержимого.

Добавьте на эту динамическую высоту ячейки и атрибутированные строки, и эти таблицы прокручиваются довольно плохо. Я предполагаю, что следующей оптимизацией было бы переопределить drawRect, но в этот момент я решил попробовать UIWebView.

UIWebView также не имеет проблем с производительностью! Его производительность прокрутки ухудшается довольно быстро по мере роста контента, однако я могу управлять этим, скрывая контент и позволяя пользователю "открывать" его по своему желанию.

Ответ 2

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

Очень близко к решению..YES

Ответ 3

Я знаю, что это старый поток, но я нашел его очень интересным, так как сейчас я просто обойдусь как разработчик iPhone, чтобы достичь таких проблем производительности. Я нашел очень интересную статью на сайте Facebook в Facebook Engineering, описывающую, как они реализовали UITableView и преодолели проблемы динамического размера, а также быстрое управление контентом. Кажется, они предварительно рассчитали использование более глубоких объектов и сохранили все асинхронные и предварительно кэшированные, где это возможно. Я собираюсь предоставить ссылку на статью, но я собираюсь скопировать раздел, который решает именно эту проблему. Надеюсь, вы сочтете это полезным. Здесь ссылка, https://www.facebook.com/notes/facebook-engineering/under-the-hood-rebuilding-facebook-for-ios/10151036091753920, и наиболее релевантная выдержка:

(Re-) Building for Speed ​​

Одним из самых больших преимуществ, которые мы получили от создания на базе iOS, была возможность быстро сделать приложение. Теперь, когда вы просматриваете новостной канал на новом Facebook для iOS, вы заметите, что он чувствует себя намного быстрее, чем раньше. Один из способов, которым мы достигли этого, - это перебалансирование, где мы выполняем определенные задачи. Например, в iOS основной поток управляет пользовательским интерфейсом и обрабатывает события касания, поэтому чем больше работы мы делаем в основном потоке, тем медленнее приложение. Вместо этого мы заботимся о выполнении дорогостоящих задач в фоновом режиме. Это означает, что вся наша сетевая активность, разбор JSON, создание NSManagedObject и сохранение на диск никогда не касаются основного потока.

Чтобы привести еще один пример, мы используем Core Text, чтобы выложить многие из наших строк, но расчеты макетов могут быстро стать узким местом. С нашим новым приложением iOS, когда мы загружаем новый контент, мы асинхронно вычисляем размеры для всех этих строк, кешируем наши CTFramesetters (которые могут быть дорогими для создания), а затем используйте все эти вычисления позже, когда мы представляем историю в нашем UITableView.

Наконец, когда вы начинаете Facebook для iOS, вы хотите видеть свою новостную ленту, а не загрузчик. Чтобы обеспечить наилучший опыт, мы теперь показываем ранее кэшированный контент. Но это вводит новую проблему: если в вашем ленте новостей много историй, UITableView бросает небольшой гаечный ключ в работу, вызывая метод делегата -tableView: heightForRowAtIndexPath: для каждой истории в ленте новостей, чтобы выяснить, как чтобы сделать свою полосу прокрутки. Это приведет к тому, что приложение загрузит все данные истории с диска и рассчитает весь макет сюжета исключительно, чтобы вернуть высоту истории, что означает, что запуск будет постепенно замедляться по мере накопления большего количества историй.

Решение этой конкретной задачи состоит из двух основных частей. Во-первых, когда мы выполняем наши первоначальные асинхронные вычисления раскладки, мы также сохраняем высоту истории в Core Data. При этом мы полностью избегаем расчета макета в -tableView: heightForRowAtIndexPath:. Во-вторых, мы разделили наш объект "истории". Мы только извлекаем высоты истории (и несколько других вещей) с диска при запуске. Позже мы извлекаем остальную часть данных истории, и все вычисления макета, которые мы должны выполнить, выполняются асинхронно.

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

Ответ 4

no 1, возможно, самая большая работа, за которой следует # 2, НО
как сказал ACB, он также является самым гибким, и IMO, несомненно, обеспечит наилучшее качество

нет 3 работает, но не будет чувствовать себя гладко/всегда будет tad 'html-ish'

no 4 звучит как шоссе в ад (позже это будет PITA для изменения/поддержки)