UIStoryboardPopoverSegue открывает несколько окон при нажатии кнопки
Я использую UIStoryboardPopoverSegue
, чтобы представить popover для iOS 5 iPad. Segue отлично работает, но похоже, что панель инструментов, содержащая кнопку, представляет собой сквозное представление для контроллера popover, поэтому, если вы продолжаете нажимать кнопку, появляется больше popovers. Поскольку я не создаю и не отслеживаю UIPopoverController
сам (как это делает Раскадровка), я не могу уволить его, когда кнопка снова коснулась. Кто-нибудь еще сталкивается с этим? У меня ошибка с Apple, но они не ответили.
EDIT. Я решил это, используя ответ ниже. Вот код, который я использовал. currentPopover
- это __weak
ivar в моем классе контроллера, поэтому, когда контроллер будет выполнен, он автоматически опустится до нуля.
- (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];
}
}
Ответы
Ответ 1
Вам нужно сохранить ссылку на свойство 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;
}
}
Затем вы можете отклонить его обычным способом.
Ответ 2
В вашем решении Cory есть некоторые проблемы с изображением.
Два варианта, которые можно рассмотреть - просто удалите или измените действие кнопки, которая представляет popover.
Вариант 1, удерживая указатель на действие кнопки, и после отображения popover установите действие равным нулю. При увольнении popover reset к исходному действию.
-(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;
}
Таким образом, popover может появляться только один раз и будет отклонен как ожидалось.
Второй вариант заключается в том, чтобы изменить функцию кнопки так, чтобы при видимости popover нажатие кнопки вызывает отклонение popover.
-(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;
}
Ответ 3
Просто подключите UIBarButtonItem
через IBAction
. Используйте set 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;
Важно: свойство привязки сека должно быть установлено на соответствующий UIBarButtonItem!
Ответ 4
Это решение также может иметь визуальные проблемы, но это не для моего простого случая. В моем случае popover просто показывал некоторую помощь. Я собрал следующее (с ARC), которое уволит контроллеры просмотра popover, когда кнопка кнопки будет нажата второй раз (как оригинал, так и вновь созданный).
- (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;
Ответ 5
Я предпочитаю использовать статическую слабую переменную, которая держит все вместе в одном месте:
- (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().
Ответ 6
14 июня 2013 года
Спасибо за редактирование. Вместо того, чтобы отклонять и воссоздавать контроллер представления - чтобы избежать проблем с производительностью и батареями и предотвратить Flash при отклонении и повторном создании контроллера представления - как насчет предотвращения появления второго экземпляра 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
Ответ 7
Это тоже хорошо.
@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;
}