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];
}
}
533   7  

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

    Ничего не найдено.