Панель инструментов UINavigationController и ориентация устройства (вращение) - PullRequest
0 голосов
/ 03 октября 2010

Итак, у меня есть это приложение для iPhone с вложенной настройкой: [RootViewController] -> [UITabBarController] -> [UINavigationController] -> [subViewControllers]. Все построено программно, а не в Интерфейсном Разработчике.

Я просто пытаюсь поддерживать все ориентации устройства. Все мои маски авторазмера настроены, и все вращается и расширяется / сжимается по мере необходимости. Все, кроме NavBar и панели инструментов NavigationController. (Обычно эти виды автоматически изменяют размер в зависимости от ориентации. То есть в альбомной ориентации панель навигации и панель инструментов должны автоматически изменять размеры примерно до 32 пикселей, а в режиме Portrai - до 44 пикселей.) Особенность заключается в том, что subView контроллера навигации изменяет размеры, но фактические navBar и панель инструментов не являются. Другими словами, содержимое растягивается / сжимается примерно на 12 пикселей или около того в любом направлении, как если бы размер панели навигации и панели инструментов изменялся. Похоже, это маски с автоматическим изменением размера, выполняющие свою работу.

Итак, чтобы попытаться разрешить эту ситуацию, я создал категорию для UINavigationController, которая отвечает на willRotateToInterfaceOrientation: duration:, чтобы активировать селектор sizeToFit. (Эта техника взята из другого поста о переполнении стека, с похожей проблемой.) В своем исследовании я обнаружил, что это сообщение получает только самый внешний контроллер представления, поэтому у меня есть вызов корневого контроллера представления на контроллере вкладок, который в свою очередь вызывает его на контроллере nav и т. д. Это решило эту проблему, и теперь мои вложенные контроллеры представления уведомляются, когда внешний вид поворачивается. Используя метод sizeToFit, размер навигационной панели и панели инструментов изменяется самостоятельно. Однако, это все еще оставляет проблему изменения положения панели инструментов, чтобы компенсировать смещение от изменения размера. (Поскольку наши координаты просмотра в iPhone начинаются сверху слева.)

Что делает этот метод сложным в методе willRotate, так это то, что у нас нет никакого способа узнать, какими будут размеры нового ограничивающего представления, и при этом мы не знаем, какова наша текущая ориентация. (Если у вас не включены deviceOrientationNotifications, чего у меня нет.) Все, с чем мы должны работать, это то, какой будет новая ориентация, и каковы текущие значения фрейма нашей панели инструментов. Я мог бы жестко запрограммировать это и вычислить настройки кадра по старинке, используя лист бумаги, но я действительно хочу сохранить функции изменения размера динамического вида, не делая никаких предположений о размерах экрана устройства.

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

@implementation UINavigationController (BLUINavigationControllerAutoRotate)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return TRUE;
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    // Resize the navBar
    [[self navigationBar] performSelector:@selector(sizeToFit)
                               withObject:nil
                               afterDelay:(0.5f * duration)];

    // Read our current frame size
    CGRect toolbarFrame = self.toolbar.frame;

    // Prevent over adjusting when flipping the device
    if ((toolbarFrame.size.height < 38
         && (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft
             || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight))
        || (toolbarFrame.size.height > 38
            && (toInterfaceOrientation == UIInterfaceOrientationPortrait
                || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)))
    {
        // We are already resized and repositioned.
        return;
    }

    // Calculate and apply the toolbar offset
    const NSInteger delta = 12;     // the difference in size between 44 and 32 px.
    toolbarFrame.origin.y += ((toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft)
                              || (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)) ? (delta) : (-delta);
    self.toolbar.frame = toolbarFrame;

    // Resize the toolbar
    [[self toolbar] performSelector:@selector(sizeToFit)
                         withObject:nil
                         afterDelay:(0.5f * duration)];

}

@end

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

Спасибо!

1 Ответ

3 голосов
/ 03 октября 2010

Вы передаете сообщение willRotateToInterfaceOrientation контроллеру представления вкладок от своего корневого контроллера представления - почему бы не передать все другие сообщения вращения и посмотреть, поможет ли это? т.е.

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [tabBarController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [tabBarController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation  {
    [super didRotateFromInterfaceOrientation:toInterfaceOrientation];
    [tabBarController didRotateFromInterfaceOrientation:toInterfaceOrientation];
}

- (void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [tabBarController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

- (void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    [super didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation];
    [tabBarController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation];
}

- (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateSecondHalfOfRotationFromInterfaceOrientation:toInterfaceOrientation duration:duration];
    [tabBarController willAnimateSecondHalfOfRotationFromInterfaceOrientation:toInterfaceOrientation duration:duration];
}

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

...