Неожиданная всплывающая анимация навигации - выпрыгивает за пределы экрана

У меня возникла проблема, из-за которой всплывающая анимация моего UINavigationController по умолчанию имеет неожиданное поведение — всплывающий контроллер иногда прыгает за пределы экрана влево или вправо.

Проблема, похоже, связана с переопределением UITraitCollection контроллера.

У меня есть универсальное приложение, а на iPad пользовательское UIPresentationController для отображения навигации в частичном модальном режиме, где его ширина составляет часть ширины экрана. Таким образом, я переопределяю horizontalSizeClass, чтобы сжать свойство overrideTraitCollection UIPresentationController, поэтому все контроллеры, представленные в этом «полумодальном режиме», принимают макет iPhone.

Переопределение этого класса размера, похоже, вызывает ошибку. Внезапно, при появлении контроллера в этом «полумодальном режиме», анимация искажается в ландшафте (она либо прыгает влево, либо вправо).

Вот пример того, как это выглядит: неожиданная-поп-анимация

Попытки

Во-первых, когда я избавляюсь от переопределения traitCollection, ошибка исчезает. Очевидно, однако, что я хочу переопределить класс горизонтального размера, потому что эти представления повторно используются в других местах и ​​в обычных средах.

Таким образом, я попытался переопределить horizontalSizeClass дочерних элементов модального окна другими способами, например:

  • Использование модального Nav UINavigationControllerDelegate для переопределения traitCollection каждого ребенка на navigationController:didShowViewController:animated: казалось, не имеет значения
  • Наличие первого дочернего элемента навигации переопределяет traitCollection вторичного дочернего элемента, прежде чем он нажмет его.

Вот так:

[self.navigationController setOverrideTraitCollection:compactTraitCollection forChildViewController:secondaryController];
[self.navigationController pushViewController:secondaryController animated:YES];

Интересно, что это исправляет ошибку всплывающей анимации, но тогда мой основной контроллер (self) все еще находится в обычном horizontalSizeClass... Кроме того, это кажется плохой практикой. Мои контроллеры представления не должны ничего знать об их представлении! Это должно обрабатываться UIPresentationController, и кажется, поддерживается тем фактом, что контроллер представления имеет свойство overrideTraitCollection.


person beebcon    schedule 05.04.2016    source источник


Ответы (1)


Оказывается, виновником была реализация supportedInterfaceOrientations, основанная на классах размеров:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    // Don't do this if you ever override size classes
    if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular)
    {
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

Поскольку horizontalSizeClass полумодальных контроллеров было переопределено для использования UIUserInterfaceSizeClassCompact, они предполагали только портретную ориентацию. Навигационный контроллер не знал, как с этим справиться.

Решение:

Изменение приведенного выше кода для зависимости от типа устройства устраняет проблему:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    // Basing off of size classes causes unexpected behavior when overriding size classes - use interface idiom instead
    if (self.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPhone)
    {
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

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

Во всяком случае, для процветания, вот тестовый проект, который я использовал для отладки: https://github.com/bradgmueller/half-modal-test

person beebcon    schedule 05.04.2016