Подтвердить что ты не робот

IOS 7 - Совет по макету

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

Однако я немного смущен относительно того, какой лучший подход к реализации этого макета.

Layout

Я попробовал несколько реализаций со смешанными результатами:

  • UIScrollView с UICollectionView в качестве подзонов: UIScrollView как родительское представление с заголовком, сегментированные элементы управления и коллекции в качестве дочерних элементов управления. Проблема с этим подходом заключается в том, что вложенная прокрутка не работает корректно. Чтобы иметь возможность прокручивать UIScrollView, крана должна находиться вне области CollectionView, иначе только свитки CollectionView и заголовок и сегментированный элемент управления не будут перемещаться.

  • Заголовок и сегментированный контроль в ячейке заголовка: Я попробовал другой подход, используя один CollectionView. Я добавил заголовок и Segmented Control в качестве подзонов одной ячейки заголовка представления коллекции. Когда измененное значение сегментации было изменено, я переключаю свойство источника данных CollectionView, чтобы получить 3 представления, необходимые для представления коллекции. Визуально все работает отлично. Единственная проблема здесь - условие гонки при быстром переключении между первой, второй и третьей вкладками. Я загружаю данные из веб-службы, если веб-служба требует времени и по-прежнему загружает данные, и я быстро переключаю вкладки, тогда я сталкиваюсь с ошибками, где возвращаемые данные предназначены для другого представления коллекции, чем то, что в настоящее время выбрано, много проблем с синхронизацией не в порядке.

  • Обновить постоянное значение для ограничения Autolayout: Другой подход, который я пытался, - изменить постоянное значение ограничения автоматического макета, применяемого к представлению "Заголовок". Затем я добавил жест в представление контроллера просмотра для отслеживания прокрутки, так как пользователь прокручивает по вертикали. Я настраиваю константу ограничения автоматического макета, чтобы ячейка "header" выходила из поля зрения. Опять же, это не работает так гладко, но я полагаю, что я могу настроить его, но это вроде как взломать.

Есть ли лучший способ реализовать этот макет?

4b9b3361

Ответ 1

Я думаю, вам нужна такая же функциональность, что и страница профиля pinterest. Чтобы реализовать такую ​​функциональность с легкостью, вам нужно выполнить следующие действия.

Шаг 1: добавьте UIView в качестве tableHeaderView тех, кто показывается при прокрутке вверх.

self.tableHeaderView = yourView

Шаг 2: добавьте UISegmentControl в виде заголовка раздела.

 - (UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section{
  return your_segmentcontrolView;

}

Шаг 3: добавьте UICollectionView в первую строку первого раздела.

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

Надеюсь, что это поможет вам.

Ответ 2

# 2 кажется хорошим решением - жесты прокрутки будут в большей степени соответствовать ожиданиям пользователей, так как все они имеют один вид прокрутки. (Я согласен, что # 3 звучит как хак.) Вы можете сделать заголовок "липким" с некоторыми атрибутами пользовательского макета.

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

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

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

Ответ 3

Альтернативный подход, который вы могли бы рассмотреть:

Используйте UITableView для размещения вашего пользовательского интерфейса

  • Создайте UITableView и установите заголовок как заголовочный файл UITableView.
  • Используйте sectionHeader для хранения сегментированного элемента управления.
  • Поместите свою коллекциюView внутри одного UITableViewCell. Или, альтернативно, вы можете использовать нижний элемент UITableView для размещения gridView.

Используя sectionHeader, это должно позволить прокручивать заголовок вне поля зрения, но затем разделHeader будет придерживаться ниже navigationBar или верхней части contentView, пока не появится другой раздел (и в вашем случае у вас будет только один раздел.)

Ответ 4

  • Добавить вид заголовка, вид тела (просмотр холдинга и просмотр коллекции) в режим прокрутки.
  • Первоначально установлено свойство userInteractionEnabled для "НЕТ" для просмотра коллекции.
  • Всегда отслеживайте насекомое в списке прокрутки.
  • Если y-координата прокрученного насекомого больше высоты заголовка, тогда установите для свойства userInteractionEnabled значение "YES", чтобы после этого можно было просмотреть прокрутку коллекции.
  • Если пользователь прокручивается за пределы прокрутки и пытается свести представление заголовка вниз, то есть просмотр прокрутки, координата y-координаты меньше высоты заголовка, затем сразу же измените режим итерации пользователя в режиме просмотра коллекции и разрешите пользователю прокручивать вид прокрутки до вершины.

Ответ 5

Вместо того, чтобы выполнять это вручную, вы можете использовать библиотеку /cocoapod, чтобы настроить это для вас. Этот выглядит очень неплохо: https://github.com/iosengineer/BMFloatingHeaderCollectionViewLayout

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

Ответ 6

Все, что я могу сказать, это то, что вам нужно подклассифицировать UIView и сделать его делегатом UIGestureRecognizerDelegate и UICollectionViewDelegate, а затем в вашем подклассе UIView, выполните следующие действия, я не могу выдавать больше информации об этом, потому что код, хотя и принадлежит сам по себе является запатентованным до такой степени, что, возможно, разгневал немало организаций, для которых я это использовал, поэтому здесь секретный соус:

CGPoint contentOffset = [scrollView contentOffset];
CGFloat newHeight = [_headerView maxHeight] - contentOffset.y;
CGRect frame = [_headerView frame];

if (newHeight > [_headerView maxHeight]) {
    frame.origin.y = contentOffset.y;
    frame.size.height = [_headerView maxHeight];
    [_headerView setFrame:frame];
} else if (newHeight < [_headerView minHeight]) {

    frame.origin.y = contentOffset.y;
    frame.size.height = [_headerView minHeight];
    [_headerView setFrame:frame];
} else {
    frame.origin.y = contentOffset.y;
    frame.size.height = newHeight;
    [_headerView setFrame:frame];
}
if ([_delegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
    return [_delegate scrollViewDidScroll:scrollView];
}

Вы должны подклассифицировать другой UIView, который определяется как заголовок для этого пользовательского UiCollectionView. Затем вы должны объявить представление пользовательского заголовка UIView внутри пользовательского поднабора делегата UIView/UICollectionView, а затем установить заголовок этого настраиваемого поднабора внутри UICollctionViewdelegate. Затем вы должны использовать этот объединенный подкласс UIView/UIcollectionView в свой UIViewController. О да, и в вашем layoutSubViews убедитесь, что вы выполняете вычисления высоты, которые проходят через двухслойный подкласс. Итак, у вас будут следующие файлы:

  • UIVew это делегат UICollectionView и то, что я упомянул ранее

  • UIView - это UISCrollViewDelegate, и это представление заголовка

  • UIViewController, который вставляет подклассы UIView в номер 1

  • Подкласс UIView числа 1, который тянет число 2 и устанавливает его как заголовок

В части номер 4 убедитесь, что вы сделали что-то вроде этого:

- (CGFloat)maxHeight
{
    if (SCREEN_WIDTH == 414)
    {
        return 260;

    }else if (SCREEN_WIDTH == 375)
    {
        return 325;

    }else
    {
        return 290;
    }
}

- (CGFloat)minHeight
{
    if (SCREEN_WIDTH == 414)
    {

        return 90;
    }else if (SCREEN_WIDTH == 375)
    {
        return 325;
    }else
    {
        return 290;
    }
}

Затем он перейдет в подкласс UIView, который является составным подклассом, как я уже объяснил. Идея состоит в том, чтобы захватить заголовок maxHeight вашего заголовка в подклассе этого заголовка UIView (номер 2 выше), а затем передать это в основной подкласс UIView, который перехватывает эти значения в scrollViewDidScroll.

Последний лакомый кусочек информации, убедитесь, что вы настроили layoutSubviews во всех методах, чтобы перехватывать события прокрутки. Например, в номере 1 выше, метод layoutsubviews таков:

- (void)layoutSubviews
{
    CGRect frame = [_headerView frame];
    frame.size.width = [self frame].size.width;
    [_headerView setFrame:frame];
    [super layoutSubviews];
}

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

Еще одно замечание. Когда вы начинаете идти по пути интенсивных реализаций, подобных этому, не удивляйтесь, узнав, что, например, один контроллер представления в приложении, который работает с такими методами, как я объяснил, будет иметь от 30-40 пользовательских подклассов которые представляют собой либо подклассы в своем собственном праве, либо сложные подклассы или подклассы моих собственных подклассов или мои собственные подклассы. Я говорю вам это, чтобы вы поняли, сколько кода требуется для правильного выбора, а не для того, чтобы напугать вас, но чтобы вы знали, что может потребоваться некоторое время, чтобы поправиться, и не пинать себя в задницу если потребуется некоторое время, чтобы сделать работу. Удачи!