在 iPad 上访问 UIActionSheet 的 UIPopoverController

发布于 2024-08-31 15:58:54 字数 297 浏览 9 评论 0原文

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

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

有谁知道获得指向弹出控制器的指针的认可方法?

提前致谢。

On the iPad, one can show a UIActionSheet using -showFromBarButtonItem:animated:. This is convenient because it wraps a UIPopoverController around the action sheet and it points the popover's arrow to the UIBarButtonItem that is passed in.

However, this call adds the UIBarButtomItem's toolbar to the list of passthrough views - which isn't always desirable. And, without a pointer to the UIPopoverController, one can't add other views to the passthrough list.

Does anyone know of a sanctioned approach to getting a pointer to the popover controller?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

a√萤火虫的光℡ 2024-09-07 15:58:55
    if ([[[[actionSheet superview] superview] nextResponder] respondsToSelector:@selector(setPassthroughViews:)]) {
        [[[[actionSheet superview] superview] nextResponder] performSelector:@selector(setPassthroughViews:) withObject:nil];
    }

就可以了,这也不会对应用程序审阅者造成任何问题,因为它不调用任何私有 API。

它很脆弱 - if 语句确保您的代码在 Apple 更改底层实现的情况下不会崩溃(只是不起作用)。

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

Will do the trick, this shouldn't cause any problems with the App Reviewers either as its not calling any private APIs.

It is fragile - the if statements ensures your code won't crash (just not work) in the unlikely event Apple change the underlying implementation.

清风挽心 2024-09-07 15:58:55

我怀疑是否有一种经过批准的方法,因为操作表是在 UIPopoverViews 中呈现的,它链接到 UIViewController 而不是 UIPopoverController

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

查看 UIPopoverView 头文件(未记录)会产生以下解决方案,尽管没有记录。怀疑你是否可以通过应用程序审阅者,但如果你认为值得一试,请尝试一下。

http://github.com/kennytm/iphone-私人框架/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];

I doubt there's a sanctioned approach to this since actionsheets are presented in UIPopoverViews which is linked to a UIViewController not a UIPopoverController

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

Looking through the UIPopoverView header file (UNDOCUMENTED) yields the following solution albeit undocumented. Doubt you can snick that past the App Reviewers but give it a go if you think it's worth a shot.

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];
以酷 2024-09-07 15:58:55

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

使用

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

示例:

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

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

I don't think that's feasible. I was sitting with the same problem.

Use

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

Example:

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

Note: You must change the index for objectAtIndex: to fit your situation and have reference to your ToolBar

她说她爱他 2024-09-07 15:58:55

这是解决方案。我刚刚发现它,而且非常简单。在显示操作表之前将 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;
}

Here is the solution. I just discovered it and it's so easy. Set userInteractionEnabled to NO before showing the action sheet and set it to YES at the end of your action sheet delegate method for dismissal.

- (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;
}
迷爱 2024-09-07 15:58:55

我已经使用 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,但您可以方便地使用完成块来执行此操作。

I've been using nbransby's answer for a couple years, but that no longer works in iOS 8. However, the problem still exists with the new UIAlertController in iOS 8. Here's an update that works for me:

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

Note that passthroughViews has to be set after the popover appears, but you can conveniently use the completion block to do that.

神爱温柔 2024-09-07 15:58:55

当从栏按钮项目呈现时,您通常希望禁用工具栏上的所有其他按钮,直到操作表消失。

我认为最简单的方法是修改 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 即可。

When presenting from a bar button item, you usually want to disable all other buttons on your toolbar until the action sheet is dismissed.

I think the simplest way to do this is to modify the UIToolbar class. You'll need a way to get hold of the actionsheet, perhaps by saving it in the app delegate.

Make a file UIToolbar+Modal.m, like this:

@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

The .h file doesn't need to contain anything special

@interface UIToolbar (Modal) {
}
@end

By the way, before finding this solution I tried assigning an empty array to passthroughViews, that you can access as (originally) described by stalinkay, but this doesn't in fact work (in addition to being undocumented).

The other ways to do this all have disadvantages - either you have to handle orientation changes, or the toolbar buttons look like they press down when in fact the only action taken is to dismiss the actionsheet.

UPDATE

As of iOS 4.3 this no longer works. You need to subclass:

UIToolbarWithModal.h

#import <Foundation/Foundation.h>

@interface UIToolbarWithModal : UIToolbar {
}

@end

Remember when you create the action sheet you need to keep it accessible, perhaps in your app delegate - in this example in the myActionSheet property.

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

Then just use UIToolbarWithModal in your code where you would have used UIToolbar before.

你另情深 2024-09-07 15:58:54

您需要根据方向变化进行调整。

我找到了一个非常适合我的替代解决方案。

坚持

- (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

我相信这会起作用。

You would need to adjust on orientation change.

I have found an alternative solution, that works perfectly for me.

Stick to

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

In your @interface add

UIActionSheet *popoverActionsheet;

also add

@property (nonatomic, retain) UIActionSheet *popoverActionsheet;

also add

- (IBAction)barButtonItemAction:(id)sender;

So you have reference to your actionsheet from anywhere in your implementation.

in your implementation

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

in your actionsheet delegate implement

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

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

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

and don't forget to release popoverActionsheet in

- (void)dealloc

I trust that this will do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文