Как вы можете создать масштабируемую временную шкалу в iOS?

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

Например, я бы хотел, чтобы это работало так: http://almende.github.com/chap-links-library/js/timeline/doc/

Какой базовый вид был бы подходящей отправной точкой для этого, имея в виду, что необходимая память должна быть как можно меньше? Будет ли для этого работать UITableView, UIScrollView или что-то еще?


person Âsgaroth    schedule 04.03.2013    source источник
comment
Этот вопрос может нуждаться в некотором редактировании, но я понимаю это, и это правильный вопрос.   -  person Luke    schedule 06.03.2013
comment
Вы рассматривали Core Plot? code.google.com/p/core-plot   -  person JRG-Developer    schedule 12.03.2013
comment
Напишите мне, если вы все еще ищете это   -  person Chris    schedule 31.05.2015


Ответы (2)


UICollectionView / UITableView не будет работать, потому что ячейки почти всегда имеют одинаковую ширину/высоту. Самое главное, что ячейки всегда имеют одинаковый интервал между ячейками. Из-за этого он может легко вычислить диапазон индекса и запросить dataSource для необходимой ячейки на основе индекса.

С другой стороны, представление временной шкалы сильно отличается от этих элементов управления. Расстояние между ячейками разное, иногда ячейки перекрывают друг друга. Если бы у вас был источник данных, отсортированный по положению, элемент управления все равно должен был бы угадать, с чего начать поиск диапазона. Таким образом, поиск правильного диапазона индексов будет более дорогим — вам просто нужно найти правильный алгоритм, чтобы определить это за более короткий промежуток времени.

Вам придется создать свой собственный элемент управления, создав подкласс UIScrollView. Вам вообще не стоит связываться с drawRect. Важным понятием, используемым UITableView и UICollectionView, является удаление ячеек из очереди. Версия Apple PhotoScroller для iOS 5 демонстрирует это. концепция с пейджингом (версия iOS 6 заменяет пользовательское пейджинг на UIPageViewController). Вам нужно будет загрузить старую документацию, чтобы получить старый пример кода.

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

- (NSInteger)numberOfCellsInTimelineView:(TimelineView *)timelineView;
- (CGRect)timelineView:(TimelineView *)timelineView cellFrameForIndex:(NSInteger)index;
- (TimelineViewCell *)timelineView:(TimelineView *)timelineView cellForIndex:(NSInteger)index;

Два из этих вызовов идентичны тому, что есть у UITableView, но у него есть новый вызов с именем cellFrameForIndex. Что важно в этом вызове, так это то, что TimelineView может угадывать индекс и искать кадр ячейки и видеть, где он помещается в видимых границах. Если он угадывает ячейку внутри видимых границ, он может просто выполнять итерацию вперед и назад, пока не найдет края.

В настоящее время алгоритм, который я использую, принимает round(count * (CGRectGetMidX(timelineView.bounds) / timelineView.contentSize.width)) (для горизонтального направления). По сути, это берет среднюю точку видимых границ UIScrollView и получает процент того, что было прокручено. Затем он умножает это на количество ячеек. Это работает достаточно хорошо. При тестировании случайного набора данных со 100 000 записей со случайным интервалом количество вызовов cellFrameForIndex варьировалось от 8 до 150. С этим я могу добиться 52-60 кадров в секунду. Я все еще работаю над этим и пытаюсь найти лучший/быстрый способ определить диапазон индекса. Я пытаюсь уменьшить количество видимых ячеек + 10 (максимум) итераций.

Если у вас есть время подождать, я обновлю свой ответ, включив ссылку на мой проект GitHub, когда закончу. Это может быть от нескольких дней до недели. Могу добавить масштабирование. Но вам придется разветвить его и добавить метки и все, что вы хотите.

Изменить:

Вот мой проект на Github: https://github.com/lukescott/TimelineView

person Luke    schedule 06.03.2013
comment
UICollectionView не делает никаких предположений о размере или расположении своих ячеек. С пользовательским UICollectionViewLayout вы можете реализовать очень гибкие макеты, которые вообще не должны быть сеткой... - person omz; 06.03.2013
comment
Интервал по-прежнему должен быть постоянным и известным, не глядя на источник данных, что является ключевым отличием. - person Luke; 06.03.2013
comment
UICollectionViewDataSource использует только indexPath. UICollectionView предполагает последовательность данных без пробелов. На временной шкале между точками могут быть промежутки (дни, месяцы, годы, пиксели). Даже если бы вы могли расширить UICollectionView для работы с временной шкалой, вам все равно нужно запросить позицию у источника данных и выяснить, каков видимый диапазон индекса. Концепция одна и та же, независимо от того, создаете ли вы что-то с нуля или расширяете UICollectionView — вам все равно нужно больше, чем количество, чтобы определить видимый диапазон для временной шкалы. - person Luke; 07.03.2013
comment
спасибо за ответы. Я добрался до базового подхода, как предложил Султан. Я действительно благодарю вас в любом случае, это было действительно полезно! - person Âsgaroth; 08.03.2013
comment
Проект Github был обновлен, чтобы включить поддержку выделения, выбора и перетаскивания. Далее я собираюсь сделать скорость прокрутки переменной. Я могу добавить вид легенды позже. Работает как вертикально, так и горизонтально. - person Luke; 12.03.2013
comment
На самом деле UICollectionView возможен. Что вам нужно, так это сопоставление между путями индекса и координатой. Пользовательский UICollectionViewLayout может иметь пользовательский источник данных, который может запрашивать это сопоставление. В настоящее время я работаю над реализацией этого. Поскольку я хочу анимировать разные макеты, для меня это должен быть UICollectionView. У меня есть основы, и я мог бы выложить его с открытым исходным кодом, как только он будет на следующем этапе. - person lammert; 30.07.2013
comment
@lammert Конечно, вы могли бы использовать layoutAttributesForElementsInRect. Вам нужно будет добавить настраиваемые вызовы делегатов для обнаружения, как это делает TimelineView. Однако вам не хватает возможности перетаскивания. Я также сделал DraggableCollectionView, но это основано на пути индекса. - person Luke; 30.07.2013

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

Я считаю, что проще всего было бы сделать все самостоятельно - реализовать это с помощью подкласса UIView с классом drawRect. Конечно, вы должны использовать UIPanRecognizer так же, как его использует UIScrollView.

person Sulthan    schedule 06.03.2013
comment
Я просто хотел бы указать, что UIScrollView более чем подходит для очень длинного контента - если вы разбиваете и повторно используете ячейки, как это делают UITableView и UICollectionView. Это означает, что все, что вы не видите, удаляется и перерабатывается. Создание подкласса UIView и переопределение drawRect не является ни простым, ни тривиальным, особенно если вы планируете взаимодействовать с элементами или анимировать движение. - person Luke; 08.03.2013
comment
@Luke То, что вы советуете делать с UIScrollView, в основном то же самое, что и с drawRect. Поверьте мне, с анимацией нет ничего сложного, поскольку все, что делает прокрутка, меняет горизонтальное и вертикальное смещение на основе данных распознавателя панорамирования. Переопределение drawRect не сложно, определенно не сложнее, чем повторное использование представлений с UIScrollView. Кроме того, это более удобно для памяти. Я только что закончил делать свой собственный прокручиваемый компонент, и не было никаких проблем с взаимодействием или анимацией. - person Sulthan; 08.03.2013
comment
@Sulthan: Конечно, вы можете это сделать, просто это не очень удобно для повторного использования, поскольку вы рисуете что-то очень конкретное. С многоразовой ячейкой вы можете создавать подклассы и помещать внутрь что угодно с минимальными усилиями. Удаление ячеек из очереди также эффективно использует память. Вы бы выиграли от рисования только в том случае, если бы у вас одновременно были сотни тысяч элементов на экране, но у вас все равно был бы запрос к источнику данных, который сам по себе является узким местом. Анимировать UIView также проще, так как это так же просто, как установить кадр один раз. - person Luke; 08.03.2013
comment
@ Люк Ну конечно. Я знаю, как использовать UITableView или UIScrollView. Однако, если у вас есть такая проблема, когда не только ячейки имеют разную ширину (не высоту — мы прокручиваем горизонтально), но даже перекрывают друг друга, то даже говорить о ячейках неправильно. Анимация UIView не менее сложна, чем анимация всего остального. Когда я в последний раз использовал это, я фактически создал подкласс слоя, и анимация была выполнена автоматически путем изменения свойства offset. Конкретные проблемы требуют конкретных решений, вы не можете сделать все универсальным, и вы не должны этого делать, если не планируете использовать это повторно. - person Sulthan; 09.03.2013
comment
Наконец-то я вернулся к использованию UIScrollview, и теперь он работает почти идеально. Пример Apple: developer.apple.com/library /ios/#samplecode/StreetScroller/ с некоторыми изменениями можно создать действительно подходящий элемент управления для приложения временной шкалы. - person Âsgaroth; 13.03.2013