Доступ к UIPopoverController для UIActionSheet на iPad - PullRequest
16 голосов
/ 11 мая 2010

На iPad можно отобразить таблицу UIActionSheet с помощью -showFromBarButtonItem: animated :. Это удобно, потому что он оборачивает UIPopoverController вокруг листа действий и указывает стрелку поповера на переданный UIBarButtonItem.

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

Кто-нибудь знает о санкционированном подходе к получению указателя на контроллер поповера?

Заранее спасибо.

Ответы [ 7 ]

10 голосов
/ 12 мая 2010

Вам необходимо отрегулировать изменение ориентации.

Я нашел альтернативное решение, которое идеально подходит для меня.

Придерживайтесь

- (void)showFromBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated

В вашем @interface добавьте

UIActionSheet *popoverActionsheet;

также добавить

@property (nonatomic, retain) UIActionSheet *popoverActionsheet;

также добавить

- (IBAction)barButtonItemAction:(id)sender;

Итак, у вас есть ссылка на лист действий из любой точки вашей реализации.

в вашей реализации

- (IBAction) barButtonItemAction:(id)sender
{
    //If the actionsheet is visible it is dismissed, if it not visible a new one is created.
    if ([popoverActionsheet isVisible]) {
        [popoverActionsheet dismissWithClickedButtonIndex:[popoverActionsheet cancelButtonIndex] 
                                                     animated:YES];
        return;
    }

    popoverActionsheet = [[UIActionSheet alloc] initWithTitle:nil
                                                     delegate:self
                                            cancelButtonTitle:nil 
                                       destructiveButtonTitle:nil
                         otherButtonTitles:@"Save Page", @"View in Safari", nil];

    [popoverActionsheet showFromBarButtonItem:sender animated:YES];
}

в вашем листе действий делегат реализует

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{

    if (buttonIndex == [actionSheet cancelButtonIndex]) return;

    //add rest of the code for other button indeces
}

и не забудьте выпустить popoverActionsheet в

- (void)dealloc

Я верю, что это подойдет.

9 голосов
/ 04 мая 2011
    if ([[[[actionSheet superview] superview] nextResponder] respondsToSelector:@selector(setPassthroughViews:)]) {
        [[[[actionSheet superview] superview] nextResponder] performSelector:@selector(setPassthroughViews:) withObject:nil];
    }

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

Это хрупко - оператор if гарантирует, что ваш код не потерпит крах (просто не будет работать) в маловероятном случае, если Apple изменит базовую реализацию.

4 голосов
/ 13 мая 2010

Я сомневаюсь, что есть санкционированный подход к этому, поскольку таблицы действий представлены в UIPopoverViews, который связан с UIViewController, а не UIPopoverController

NSLog(@"%@",[[[popoverActionsheet superview] superview] passthroughViews]);

Просмотр заголовочного файла UIPopoverView (UNDOCUMENTED) дает следующее решение, хотя и недокументированное. Сомневаюсь, что вы можете пробить это мимо рецензентов приложений, но попробуйте, если считаете, что это стоит того.

http://github.com/kennytm/iphone-private-frameworks/blob/master/UIKit/UIPopoverView.h

NSArray *passthroughViews = [[[popoverActionsheet superview] superview] passthroughViews];

        NSMutableArray *views = [passthroughViews mutableCopy];
        [views addObject:[self view]];
        [[[popoverActionsheet superview] superview] setPassthroughViews:views];
        [views release];
2 голосов
/ 23 декабря 2014

Я использую ответ nbransby в течение пары лет, но он больше не работает в iOS 8. Однако проблема все еще существует с новым UIAlertController в iOS 8. Вот обновление, которое работает для меня:

UIAlertController *actionSheet = [UIAlertController
    alertControllerWithTitle:@"Test"
    message:@"Hello, world!"
    preferredStyle:UIAlertControllerStyleActionSheet];
[actionSheet addAction:[UIAlertAction
    actionWithTitle:@"OK"
    style:UIAlertActionStyleDefault
    handler:^(UIAlertAction *action) {}]];
actionSheet.modalPresentationStyle = UIModalPresentationPopover;
actionSheet.popoverPresentationController.barButtonItem = testButton;
[self presentViewController:actionSheet animated:TRUE completion:^(void) {
    actionSheet.popoverPresentationController.passthroughViews = [NSArray array];
}];

Обратите внимание, что passthroughViews должен быть установлен после появления всплывающего окна, но вы можете удобно использовать блок завершения для этого.

2 голосов
/ 15 апреля 2013

Вот решение. Я только что открыл это, и это так просто. Установите для userInteractionEnabled значение NO, прежде чем показывать лист действий, и задайте для него значение YES в конце метода делегирования листа действий для исключения.

- (void)promptResetDefaults:(id)sender
{
    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
                                                             delegate:self
                                                    cancelButtonTitle:nil
                                               destructiveButtonTitle:NSLocalizedString(@"Reset All Defaults", nil)
                                                    otherButtonTitles:nil];

    self.navigationController.navigationBar.userInteractionEnabled = NO;
    [actionSheet showFromBarButtonItem:sender animated:YES];
}

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == actionSheet.destructiveButtonIndex)
    {
        [self.dataDefaults resetDataDefaults];
        [self.tableView reloadData];
    }

    self.navigationController.navigationBar.userInteractionEnabled = YES;
}
2 голосов
/ 11 мая 2010

Я не думаю, что это возможно. Я сидел с той же проблемой.

Использование

- (void)showFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated

Пример:

[actionSheet showFromRect:[[[myToolBar subviews] objectAtIndex:0] frame] inView:myToolBar animated:YES];

Примечание: вы должны изменить индекс для objectAtIndex: чтобы соответствовать вашей ситуации и иметь ссылку на вашу панель инструментов

1 голос
/ 05 ноября 2010

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

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

Создайте файл UIToolbar + Modal.m, например:

@implementation UIToolbar (Modal)

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
  UIView *hitView = [super hitTest:point withEvent:event];

  UIActionSheet *mySheet = [[[UIApplication sharedApplication] delegate] myActionSheet];
  if ([mySheet isVisible]) return nil;
  else return hitView;
}

@end

Файл .h не должен содержать ничего особенного

@interface UIToolbar (Modal) {
}
@end

Кстати, прежде чем найти это решение, я попытался назначить пустой массив для passthroughViews, к которому вы можете обращаться, как (изначально) описано в stalinkay, но на самом деле это не работает (в дополнение к отсутствию документов). *

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

UPDATE

Начиная с iOS 4.3 это больше не работает. Вы должны подкласс:

UIToolbarWithModal.h

#import <Foundation/Foundation.h>

@interface UIToolbarWithModal : UIToolbar {
}

@end

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

UIToolbarWithModal.m

#import "UIToolbarWithModal.h"
#import "MyDelegate.h"

@implementation UIToolbarWithModal

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
  UIView *hitView = [super hitTest:point withEvent:event];

  UIActionSheet *mySheet = [[[UIApplication sharedApplication] delegate] myActionSheet];
  if ([mySheet isVisible]) return nil;
  else return hitView;
}

@end

Тогда просто используйте UIToolbarWithModal в своем коде, где вы уже использовали UIToolbar.

...