Кнопка "Закрыть" на адаптивной навигации
В раскадровке у меня есть контроллер корневого представления с кнопкой, которая запускает "Present as Popover" в UINavigationController, содержащий UITableViewController. Я хочу, чтобы навигационный контроллер присутствовал как на iPhone, так и на iPad.
На iPad это отлично работает в popover.
На iPhone я получаю модальную презентацию, поэтому теперь мне нужно добавить дополнительную кнопку панели, чтобы отклонить модальное представление. От просмотра видео WWDC я попытался выполнить следующие действия в контроллере корневого представления:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController *vc = segue.destinationViewController;
vc.popoverPresentationController.delegate = self;
}
- (void)dismissPopover {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style {
UINavigationController *nvc = (UINavigationController *)controller.presentedViewController;
UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(dismissPopover)];
nvc.topViewController.navigationItem.leftBarButtonItem = bbi;
return nvc;
}
Я понимаю, что метод -presentationController:viewControllerForAdaptivePresentationStyle:
должен вызываться только тогда, когда пользовательский интерфейс является адаптивным, т.е. модальным, однако он вообще не называется вызываемым, даже если он работает как модальный на iPhone.
Ответы
Ответ 1
Хорошо, мне удалось заставить его работать. Я думаю, что моя проблема заключалась в том, что свойство popoverPresentationController
проходит иерархию представлений контроллера до тех пор, пока не найдет контроллер вида с popoverPresentationController
, т.е. если у меня есть контроллер представления внутри контроллера навигации внутри popover, контроллер вида popoverPresentationController
будет перейдите к контроллеру nav и используйте его свойство. Чтобы это работало, контроллер просмотра должен быть дочерним элементом навигационного контроллера. Во всех точках, которые я пытался использовать popoverPresentationController
, это было не так, например init
, viewDidLoad
, viewWillAppear
. По какой-то причине willMoveToParentViewController
не вызывается, хотя вызов didMove
вызывает. Поэтому я не знаю, как ссылаться на popoverPresentationController
в vc внутри контроллера nav до того, как будут вызваны методы делегата ppc.
Однако, вы можете ссылаться на него в контроллере представления в prepareForSegue
, но вам нужно явно указать, какой стиль презентации использовать. Здесь мой код, который работает при размещении в представлении контроллера представления:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController *dest = segue.destinationViewController;
dest.popoverPresentationController.delegate = self;
}
- (void)dismiss {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationFullScreen; // required, otherwise delegate method below is never called.
}
- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style {
// If you don't want a nav controller when it a popover, don't use one in the storyboard and instead return a nav controller here
UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(dismiss)];
UINavigationController *nc = (UINavigationController *)controller.presentedViewController;
nc.topViewController.navigationItem.leftBarButtonItem = bbi;
return controller.presentedViewController;
}
Ответ 2
Здесь версия Swift версии Nick правильно отвечает тем, кто хочет быстро вырезать и вставить.
Примечание. Это делается для создания всплывающего окна на вашем iPad, но модального листа с кнопкой закрытия на вашем iPhone.
В раскадровке Xcode 6.3 вы подключаете контроллер вида и обозначаете segue как "Present as Popover"
Нижеприведенный код должен идти в контроллере представления, который перебирается к popover, а не к самому popover:
Сначала вы настроили делегат popover:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "myPopoverSegueName") {
let vc = segue.destinationViewController
vc.popoverPresentationController?.delegate = self
return
}
}
Затем вы добавляете расширение делегата и нажимаете кнопку навигации/закрытия на лету:
extension myViewController: UIPopoverPresentationControllerDelegate {
func presentationController(controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
let btnDone = UIBarButtonItem(title: "Done", style: .Done, target: self, action: "dismiss")
let nav = UINavigationController(rootViewController: controller.presentedViewController)
nav.topViewController.navigationItem.leftBarButtonItem = btnDone
return nav
}
}
Затем вы добавляете функцию увольнения, и вам должно быть хорошо:
func dismiss() {
self.dismissViewControllerAnimated(true, completion: nil)
}
Ответ 3
Я обнаружил, что принятый ответ неправильно отображает кнопку "done" в компактном режиме (например, iPhone), но остается как popover в обычном режиме (например, IPAD).
Следующий код является минимальным для выполнения этой работы - поместите их в класс контроллера представления.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController *dest = segue.destinationViewController;
dest.popoverPresentationController.delegate = self;
}
- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style {
UIViewController* presentedViewController = controller.presentedViewController;
if ([controller isKindOfClass:[UIPopoverPresentationController class]] && style == UIModalPresentationFullScreen) {
UINavigationController* navCtrl = [[UINavigationController alloc] initWithRootViewController:presentedViewController];
UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(dismiss:)];
presentedViewController.navigationItem.rightBarButtonItem = bbi;
return navCtrl;
}
return presentedViewController;
}
-(IBAction)dismiss:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
Обратите внимание на три отличия с принятым ответом:
- Нам не нужно переопределять
adaptivePresentationStyleForPresentationController:
- Мы проверяем, является ли диспетчер презентации popover, но запрашивает полноэкранный режим.
- Мы возвращаем новый экземпляр контроллера навигации вместо (некорректно) литья представленного контроллера представления в качестве навигационного контроллера.