Скрытие наложения UISplitViewController в портретной ориентации

Применяя новый UISplitViewController, я пытаюсь изменить поведение по умолчанию, возникающее при использовании режима UISplitViewControllerDisplayModeAutomatic.

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

Я попытался использовать следующее с делегатом:

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(id)sender
{
    if (splitViewController.displayMode == UISplitViewControllerDisplayModePrimaryOverlay) {
        [UIView animateWithDuration:0.3 animations:^{
            splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden;
        }];
    }
    return NO;
}

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

Как я могу вручную вызвать закрытие оверлея?

Примечание о дублировании: iOS8 полностью изменился UISplitViewController, поэтому все другие ответы SO до июня 2014 года, вероятно, неверны (и я перерыл многие из них, на всякий случай)


person Parrots    schedule 28.08.2014    source источник


Ответы (5)


У меня была такая же проблема, как у вас. Я делаю это на моносенсорной платформе Xamarin, но я думаю, что результат будет таким же.

Как сказал LaborEtArs, переместите свой код в метод prepareForSegue:sender: главного контроллера представления. Затем просто установите автоматический режим после того, как вы установили его в скрытый:

if (splitViewController.displayMode == UISplitViewControllerDisplayModePrimaryOverlay) {
    splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden;
    splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
}

После этого он больше не нарушает ландшафтный режим.

person Cory Juhlin    schedule 11.11.2014

Просто поместите свой код (без return NO;) в метод контроллеров главного представления prepareForSegue:sender: или tableView:didSelectRowAtIndexPath:. Там он работает идеально!

person LaborEtArs    schedule 31.10.2014
comment
Хороший простой ответ. Я обнаружил, что продолжительность 0,3 немного медленнее по сравнению с анимацией, когда вы включаете или отключаете свайпом или кнопкой; 0,2 секунды кажется правильным. - person Nick; 09.11.2014
comment
Это прекрасно работает, но если основной вид отображается, когда устройство поворачивается в альбомную ориентацию, размер подробного вида не изменяется должным образом. - person Leon; 02.07.2015

В дополнение к совету от LaborEtArs выполнять анимацию в prepareForSegue:sender: или tableView:didSelectRowAtIndexPath:, если в вашем приложении обычно splitViewController:preferredDisplayMode установлено на UISplitViewControllerDisplayModeAutomatic, просто используйте метод animateWithDuration: с обработчиком завершения, чтобы восстановить displayMode после анимации:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"showDetail"]) {

        // configure the detail controller

        if (self.splitViewController.displayMode == UISplitViewControllerDisplayModePrimaryOverlay) {
            [UIView animateWithDuration:0.3 animations:^{
                self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden;
            } completion:^(BOOL finished){
                self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
        }];
    }
}
person JBJr    schedule 20.02.2016
comment
Анимация действительно важна для того, чтобы это произошло. Престижность. Однако размещение этого в didSelectRowAtIndexPath вызывает странную детальную анимацию табличного представления (нежелательно). Размещение его в prepareForSegue:sender приводит к блестящей анимации. - person David; 18.04.2016

Вот версия Swift:

if (self.splitViewController?.displayMode == UISplitViewControllerDisplayMode.PrimaryOverlay){
    splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden
    splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.Automatic
} else {
    println(self.splitViewController?.displayMode)
}

Помещено в prepareForSegue

person Alexecc    schedule 03.12.2014

iOS 13 и более поздние версии

Этот метод не находится в общедоступном заголовке, но вы можете добавить его следующим образом:

@interface UISplitViewController()
- (void)toggleMasterVisible:(id)sender;
@end

До iOS 13

Раньше я использовал этот способ, но больше не работает в новом UISplitViewControllerPanelImpl iOS 13:

@interface AppDelegate ()
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@property (nonatomic, assign) UIPopoverController *splitPopoverController;
#pragma clang diagnostic pop
@end

@implementation AppDelegate

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (void)splitViewController:(UISplitViewController *)splitViewController popoverController:(UIPopoverController *)popoverController willPresentViewController:(UIViewController *)vc{
#pragma clang diagnostic pop
    self.splitPopoverController = popoverController;
}

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(nullable id)sender{
    [self.splitPopoverController dismissPopoverAnimated:YES];
    return NO;
}

@end
person malhal    schedule 20.11.2018