2010-05-10 4 views
16

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

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

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

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

ответ

2

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

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

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

Пример:

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

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

+0

Это связано с изменением ориентации? Или вам нужно настроить события поворота? Спасибо. – westsider

10

Вам необходимо будет настроить при изменении ориентации.

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

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

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

в вашем actionsheet делегатом реализации

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

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

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

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

- (void)dealloc 

Я надеюсь, что это будет делать.

+1

Сталинкай, спасибо. То, что вы описываете, близко к тому, что я делаю сейчас. Я должен был быть более конкретным. У меня есть лист действий, показанный с помощью кнопки на панели инструментов внизу экрана. У меня также есть панель навигации в верхней части экрана. Я бы хотел, чтобы кнопки на панели навигации вел себя одинаково (относительно листа действий) в виде кнопок на панели инструментов. Другими словами, я бы хотел, чтобы кнопки на панели навигации находились в списке проходов pop-pop-pop-профайла, и чтобы иметь краны в кнопках навигационных баров *, оба * отключают действие листа * и * кнопку кнопки управления. Именно поэтому получение указателя на popover важно. – westsider

4

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

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

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

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]; 
+0

Я думаю, что это то, что я искал - на каком-то уровне. Это, очевидно, хрупко до такой степени, что Apple может изменить базовую реализацию, скажем, добавить еще один уровень просмотров и т. Д. У меня возникает соблазн написать свою собственную версию с popover. Когда я обойдусь, я отправлю код здесь. Спасибо, снова! – westsider

+0

Отлично. Хотелось бы посмотреть, что вы придумали. – stalinkay

1

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

Я думаю, что самый простой способ сделать это - изменить класс 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 

заголовочный файл не должен содержать ничего особенного

@interface UIToolbar (Modal) { 
} 
@end 

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

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

UPDATE

С прошивкой 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 раньше.

9
if ([[[[actionSheet superview] superview] nextResponder] respondsToSelector:@selector(setPassthroughViews:)]) { 
     [[[[actionSheet superview] superview] nextResponder] performSelector:@selector(setPassthroughViews:) withObject:nil]; 
    } 

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

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

+0

Это хорошее решение. Интересно, почему Apple добавляет планку в passthroughviews в первую очередь. – DrMickeyLauer

+0

Это не работает для меня на iOS 6. Контроллер popover не находится в цепочке ответчиков. –

+1

Работайте отлично для меня на iOS 6! Он должен быть вызван после представления листа действий. – ToddH

2

Вот решение. Я только что открыл его, и это так просто. Установите userInteractionEnabled в НЕТ, прежде чем показывать лист действий и установите для него значение 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; 
} 
+0

Очень хорошо обход (может быть, даже самый лучший здесь). Я не знаю, почему люди не поддерживают это. – Byte

2

Я никогда использовал ответ nbransby в течение нескольких лет, но это больше не работает в прошивке 8. Тем не менее, проблема все еще существует с прошивкой в ​​8 новых UIAlertController.Вот обновление, которое работает для меня:

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 должен быть установлен после того, как появится поповер, но вы можете удобно использовать блок завершения, чтобы сделать это.

Смежные вопросы