在iPad上访问UIActionSheet的UIPopoverController

时间:2010-05-10 22:51:28

标签: ipad uipopovercontroller uiactionsheet

在iPad上,可以使用-showFromBarButtonItem:animated:来显示UIActionSheet。这很方便,因为它将UIPopoverController包装在操作表周围,并将弹出框的箭头指向传入的UIBarButtonItem。

但是,此调用将UIBarButtomItem的工具栏添加到直通视图列表中 - 这并不总是令人满意的。并且,如果没有指向UIPopoverController的指针,则无法将其他视图添加到直通列表中。

有没有人知道获得指向弹出控制器的指针的制裁方法?

提前致谢。

7 个答案:

答案 0 :(得分:10)

您需要调整方向更改。

我找到了另一种解决方案,对我来说非常适合。

坚持

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

在@interface add

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

我相信这样做。

答案 1 :(得分:9)

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

可以解决这个问题,这不应该导致App Reviewers出现任何问题,因为它不会调用任何私有API。

它很脆弱 - if语句确保你的代码不会崩溃(只是不起作用),万一Apple改变底层实现。

答案 2 :(得分:4)

我怀疑是否有一个受制裁的方法,因为操作表在UIPopoverViews中呈现,它链接到UIViewController而不是UIPopoverController

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

查看UIPopoverView头文件(UNDOCUMENTED)会产生以下解决方案,尽管没有记录。怀疑你可以通过App Reviewers嗤之以鼻,但如果你觉得它值得一试,那就试一试。

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

答案 3 :(得分:2)

我认为这不可行。我遇到了同样的问题。

使用

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

示例:

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

注意:您必须更改objectAtIndex的索引:以适合您的情况并引用您的ToolBar

答案 4 :(得分:2)

这是解决方案。我刚发现它并且它很容易。在显示操作表之前将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;
}

答案 5 :(得分:2)

我已经使用nbransby的答案了几年,但是在iOS 8中不再有效。但是,iOS 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,但您可以方便地使用完成块来执行此操作。

答案 6 :(得分: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

.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

然后在您之前使用过UIToolbar的代码中使用UIToolbarWithModal。