Доступ к UIPopoverController для UIActionSheet на iPad
На iPad можно показать таблицу UIActionSheet, используя -showFromBarButtonItem: animated:. Это удобно, потому что он обертывает UIPopoverController вокруг листа действий и указывает стрелку popover на UIBarButtonItem, который передан.
Тем не менее, этот вызов добавляет панель инструментов UIBarButtomItem в список представлений пересылки - что не всегда желательно. И, не указав на UIPopoverController, нельзя добавить другие представления в список переходов.
Кто-нибудь знает о санкционированном подходе к указанию на контроллер popover?
Спасибо заранее.
Ответы
Ответ 1
Вам нужно будет отрегулировать изменение ориентации.
Я нашел альтернативное решение, которое отлично работает для меня.
Придерживайтесь
- (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
Я верю, что это будет сделано.
Ответ 2
if ([[[[actionSheet superview] superview] nextResponder] respondsToSelector:@selector(setPassthroughViews:)]) {
[[[[actionSheet superview] superview] nextResponder] performSelector:@selector(setPassthroughViews:) withObject:nil];
}
Сделаем трюк, это не должно вызывать никаких проблем с Рецензентами приложений, поскольку он не вызывает каких-либо частных API.
Он хрупкий - операторы if гарантируют, что ваш код не будет сбой (просто не работает) в маловероятном случае Apple изменит базовую реализацию.
Ответ 3
Я сомневаюсь, что существует санкционированный подход к этому, поскольку таблицы действий представлены в UIPopoverViews, который связан с UIViewController, а не с UIPopoverController
NSLog(@"%@",[[[popoverActionsheet superview] superview] passthroughViews]);
Просматривая заголовочный файл UIPopoverView (UNDOCUMENTED), выдается следующее решение, хотя и недокументированное. Сомневайтесь, что вы можете хихикать, что мимо Рецензентов App, но отпустите его, если вы считаете, что это стоит того.
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];
Ответ 4
Я не думаю, что это возможно. Я сидел с той же проблемой.
Используйте
- (void)showFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated
Пример:
[actionSheet showFromRect:[[[myToolBar subviews] objectAtIndex:0] frame] inView:myToolBar animated:YES];
Примечание. Вы должны изменить индекс для объектаAtIndex: чтобы соответствовать вашей ситуации и иметь ссылку на ваш ToolBar
Ответ 5
Вот решение. Я только что открыл его, и это так просто. Установите 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;
}
Ответ 6
Я использую ответ 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 должен быть установлен после появления popover, но вы можете удобно использовать блок завершения для этого.
Ответ 7
При представлении из элемента кнопки панели вы обычно хотите отключить все остальные кнопки на панели инструментов, пока лист действий не будет отклонен.
Я думаю, что самый простой способ сделать это - изменить класс 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, но на самом деле это не работает (в дополнение к недокументированности).
Другие способы сделать это все имеют недостатки - либо вы должны обрабатывать изменения ориентации, либо кнопки на панели инструментов выглядят так, как будто они нажимают вниз, когда на самом деле единственным действием является отклонение листа действий.
ОБНОВЛЕНИЕ
Начиная с 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.