UIStoryboardPopoverSegue открытие нескольких окон при нажатии кнопки
Я использую UIStoryboardPopoverSegue, чтобы представить поповер для приложения iOS 5 iPad. Сегмент работает отлично, но кажется, что панель инструментов, содержащая кнопку, является видом passthrough для контроллера popover, поэтому, если вы продолжаете нажимать кнопку, появляется больше всплывающих окон. Поскольку я не создаю и не отслеживаю UIPopoverController сам (как это делает раскадровка), я не могу отмахнуться от него, когда кнопка снова нажата. Кто - нибудь еще сталкивался с этим? У меня есть ошибка, открытая с Apple, но они не имеют ответил.
EDIT : я решил эту проблему, используя ответ ниже. Вот код, который я в итоге использовал. currentPopover - это __weak Ивар в моем классе контроллера, поэтому, когда контроллер будет выполнен, он автоматически опустится до нуля.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue isKindOfClass:[UIStoryboardPopoverSegue class]]){
// Dismiss current popover, set new popover
[currentPopover dismissPopoverAnimated:YES];
currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
}
}
7 ответов:
Необходимо сохранить ссылку на свойство
popoverController, переданное как часть классаUIStoryboardPopoverSegueв методе классаprepareForSegue.Чтобы получить к нему доступ, переверните метод в вызывающем контроллере вида следующим образом:
Тогда вы можете отклонить его обычным способом.- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // The Storyboard Segue is named popover in this case: if ([segue.identifier compare:@"popover"] == NSOrderedSame) { // segue.popoverController is only present in popover segue's // self.seguePopoverController is a UIPopoverController * property. self.seguePopoverController = segue.popoverController; } }
Есть некоторые визуальные проблемы с вашим решением Кори.
Два варианта, которые можно рассмотреть-просто удалить или изменить действие кнопки, которая представляет поповер.
Вариант 1, удерживая указатель на действие кнопки, и после того, как всплывающее окно будет представлено, установите действие равным нулю. При увольнении поповер сбрасывается на исходное действие.
Таким образом, поповер может появиться только один раз и будет отклонен, как и ожидалось.-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { action = [sender action]; [sender setAction:nil]; self.currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController]; self.currentPopover.delegate = self; } -(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController { [self.navigationItem.rightBarButtonItem setAction:action]; return YES; }Второй вариант был бы следует изменить функцию кнопки так, чтобы, когда всплывающее окно будет видно, нажатие кнопки приведет к тому, что всплывающее окно будет отклонено.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { action = [sender action]; target = [sender target]; [sender setTarget:self]; [sender setAction:@selector(dismiss:)]; self.currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController]; self.currentPopover.delegate = self; } -(void)dismiss:(id)sender { [self.navigationItem.rightBarButtonItem setAction:action]; [self.navigationItem.rightBarButtonItem setTarget:target]; ////or // [sender setAction:action]; // [sender setTarget:target]; [self.currentPopover dismissPopoverAnimated:YES]; } -(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController { [self.navigationItem.rightBarButtonItem setAction:action]; [self.navigationItem.rightBarButtonItem setTarget:target]; return YES; }
Просто соедините
UIBarButtonItemчерезIBAction. Используйте набор itendifier в построителе интерфейсов:-(IBAction)barButtonItemPressed:(id)sender { if (currentPopoverController && currentPopoverController.popoverVisible) { [currentPopoverController dismissPopoverAnimated:YES]; currentPopoverController = nil; } else { [self performSegueWithIdentifier:@"aSegueIdentifier" sender:sender]; } }Получить ссылку на новый
UIPopoverCOntrollerиз seque:-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"aSegueIdentifier"]) currentPopoverController = [(UIStoryboardPopoverSegue *)segue popoverController]; }
currentPopoverControllerявляется переменной экземпляра, определенной в заголовочном файле:UIPopoverController *currentPopoverController;Важно: якорное свойство seque должно быть установлено в соответствующее UIBarButtonItem!
Это решение также может иметь визуальные проблемы, но это не так для моего простого случая. В моем случае поповер просто показывал некоторую помощь. Я собрал следующие (с ARC), которые будут отклонять всплывающие видоконтроллеры, когда кнопка панели кнопок будет нажата во второй раз (как исходная, так и вновь созданная).
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if( [segue isKindOfClass:[UIStoryboardPopoverSegue class]] ) { UIStoryboardPopoverSegue *popoverSegue = (id)segue; UIPopoverController *popoverController = popoverSegue.popoverController; if( m_popoverController.popoverVisible ) { [m_popoverController dismissPopoverAnimated:NO]; dispatch_async( dispatch_get_main_queue(), ^{ [popoverController dismissPopoverAnimated:YES]; }); m_popoverController = nil; } else m_popoverController = popoverController; } }Я также добавил некоторую очистку в dealloc
- (void)dealloc { if( m_popoverController.popoverVisible ) [m_popoverController dismissPopoverAnimated:YES]; }Для этого требуется переменная-член в вашем классе
UIPopoverController *m_popoverController;
Я предпочитаю использовать статическую слабую переменную, которая удерживает все вместе в одном месте:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"showSomething"]) { static __weak UIPopoverController* currentPopover = nil; [currentPopover dismissPopoverAnimated:NO]; currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController]; // ... } }Нет никаких причин добавлять отдельную дополнительную переменную (когда у вас будет несколько экземпляров контроллера вида?), и таким образом вы можете добавить дополнительную переменную для каждого блока if ().
14 июня 2013
Спасибо за редактирование в вопросе. Вместо того чтобы отклонять и воссоздавать контроллер вида-чтобы избежать проблем с производительностью и батареей и предотвратить вспышку при отклонении и воссоздании контроллера вида-как насчет предотвращения второго экземпляра popover от появления?
//place in view controller (tested iOS6+, iPad, iPhone) __weak UIPopoverController *popover; - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if([segue isKindOfClass:[UIStoryboardPopoverSegue class]] && [segue.identifier isEqualToString:@"mySegue"]) //remember to change "mySegue" popover = [(UIStoryboardPopoverSegue *)segue popoverController]; } - (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender { if ([identifier isEqualToString:@"mySegue"]) //remember to change "mySegue" return !popover; else return YES; } added checks to: http://stackoverflow.com/a/10238581/1705353
Это тоже хорошо.
@interface ViewController : UIViewController <UIPopoverControllerDelegate> { UIPopoverController * seguePopoverController; } @property (strong) UIPopoverController * seguePopoverController; @end - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if (self.seguePopoverController) { [self.seguePopoverController dismissPopoverAnimated:NO]; self.seguePopoverController = nil; } // The Storyboard Segue is named popover in this case: if ([[segue identifier] isEqualToString:@"popover"]) { UIStoryboardPopoverSegue* popSegue = (UIStoryboardPopoverSegue*)segue; UIPopoverController *thePopoverController = [popSegue popoverController]; thePopoverController.delegate = self; self.seguePopoverController = thePopoverController; } } - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController { self.seguePopoverController = nil; }
Comments