如何使用UIAlertController替换UIActionSheet?

55

我正在维护一个基于SDK 6.0的旧iOS项目。

该项目中有一个名为

-(void) showComboBox:(UIView*)view:withOptions:(NSDictionary*)options

的方法,用于显示下拉框。为了实现这个目标,它使用了在iOS8上已被弃用的UIActionSheet。

我的解决方案如下:

        if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8) {
        UIAlertController* alertController = [UIAlertController 
           alertControllerWithTitle:@"title" 
           message:@"message" 
           preferredStyle:UIAlertControllerStyleActionSheet];

        UIAlertAction* item = [UIAlertAction actionWithTitle:@"item" 
           style:UIAlertActionStyleDefault 
           handler:^(UIAlertAction *action) {
            //do something here 
            //inform the selection to the WebView 
            ...
            [alertController dismissViewControllerAnimated:YES completion:nil];
        }];

        UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            [alertController dismissViewControllerAnimated:YES completion:nil];
        }];

        [alertController addAction:item];
        [alertController addAction:cancelAction];
        //I am not sure whether it's the right way
        if ([view.nextResponder isKindOfClass:UIViewController.class]) {
            UIViewController* vc = (UIViewController*)view.nextResponder;
            [vc presentViewController:alertController animated:YES completion:nil];
        }

这是我最关注的问题:需要将UIAlertController添加到UIViewController中,但我只能获取UIView的指针,所以我使用了view.nextResponder来获得我想要的东西,但这是一个好方法吗?

6个回答

77

我已经使用以下代码通过UIAlertViewController显示操作表,并且它运行得非常完美。

Swift

let alert = UIAlertController(title: "Action Title", message: "Action Message", preferredStyle: .actionSheet)
let action = UIAlertAction(title: "Item", style: .default) {
    UIAlertAction in
    // Write your code here
}
alert.addAction(action)

let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) {
    UIAlertAction in
    // It will dismiss action sheet
}
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)

Objective C

- (IBAction)buttonClicked:(id)sender {

    UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:@"Action Sheet" message:@"Using the alert controller" preferredStyle:UIAlertControllerStyleActionSheet];

    [actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {

        // Cancel button tappped.
        [self dismissViewControllerAnimated:YES completion:^{
        }];
    }]];

    [actionSheet addAction:[UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {

        // Distructive button tapped.
        [self dismissViewControllerAnimated:YES completion:^{
        }];
    }]];

    [actionSheet addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {

        // OK button tapped.

        [self dismissViewControllerAnimated:YES completion:^{
        }];
    }]];

    // Present action sheet.
    [self presentViewController:actionSheet animated:YES completion:nil];
}

编辑:

你需要在这里获取UIViewController对象。你可以设置全局变量或调用委托方法,或者你可以使用通知来获取此代码中的视图控制器对象。

上面代码的最后一行将是这样的。

[self.viewController presentViewController:actionSheet animated:YES completion:nil];

self.viewController 是一个全局变量,将在获取该视图之前设置。

因为您现在正在使用 view.nextResponder 的方法,我担心它可能无法正常工作。


几乎一样,只有一点不同:我无法直接获取UIViewController的指针,因此我必须使用UIView.nextResponder,我想知道这是否正确。 - Don_Chen
你的代码中的 view 是什么?它是任何视图控制器的子视图吗? - Kampai
但是设置一个全局变量或调用委托方法都意味着很多改变,而且项目看起来会很奇怪。为什么使用view.nextResponder是个坏主意?我已经进行了一些测试,似乎工作得很好。 - Don_Chen
呃...我只是不记得UIAlertController不适用于iOS7了,我的错。 - Don_Chen
2
@Kampai 谢谢你的答案。非常简单易懂,节省了我的时间。 - Jagat Dave
显示剩余4条评论

29

我曾使用操作表来更改个人资料照片。我遵循了Kampai的方法,只是移除了dismissviewController调用,因为它在按下取消或照片选择视图时将我踢出了视图

UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];

[actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {

    // Cancel button tappped do nothing.

}]];

[actionSheet addAction:[UIAlertAction actionWithTitle:@"Take photo" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {

    // take photo button tapped.
    [self takePhoto];

}]];

[actionSheet addAction:[UIAlertAction actionWithTitle:@"Choose photo" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {

    // choose photo button tapped.
    [self choosePhoto];

}]];

[actionSheet addAction:[UIAlertAction actionWithTitle:@"Delete Photo" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {

    // Distructive button tapped.
    [self deletePhoto];

}]];

14

Swift更新 -

    let actionSheet = UIAlertController.init(title: "Please choose a source type", message: nil, preferredStyle: .actionSheet)
    actionSheet.addAction(UIAlertAction.init(title: "Take Photo", style: UIAlertActionStyle.default, handler: { (action) in
        self.openCamera()
    }))
    actionSheet.addAction(UIAlertAction.init(title: "Choose Photo", style: UIAlertActionStyle.default, handler: { (action) in
        self.showPhotoLibrary()
    }))
    actionSheet.addAction(UIAlertAction.init(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { (action) in
        // self.dismissViewControllerAnimated(true, completion: nil) is not needed, this is handled automatically,
         //Plus whatever method you define here, gets called,
        //If you tap outside the UIAlertController action buttons area, then also this handler gets called.
    }))
    //Present the controller
    self.present(actionSheet, animated: true, completion: nil)

5

Swift 4

        let alert = UIAlertController(title: "Select One", message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)
        alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
        alert.addAction(UIAlertAction(title: "Export", style: UIAlertActionStyle.default, handler: { (action) in

            // TODO: Export wordlist

        }))
        alert.addAction(UIAlertAction(title: "Import", style: UIAlertActionStyle.default, handler: { (action) in

            // TODO: Import wordlist
        }))

        self.present(alert, animated: true, completion: nil)

0

虽然看起来非常简单,但使用UIAlertController存在一个令人讨厌的问题,即容易出现内存泄漏。为了测试是否存在此问题,只需在您的视图控制器的dealloc方法处设置断点,查看它是否被正确释放。

我寻找解决方案已经有一段时间了,以下是我在应用程序中使用警报控制器的方法。

+ (void)alertWithPresenting:(UIViewController *)presenting title:(NSString *)title
                       text:(NSString *)text buttons:(NSArray *)buttons
                    handler:(void (^)(UIAlertAction *action, NSUInteger index))handler
{
        UIAlertController *alert = [UIAlertController
                                    alertControllerWithTitle:title message:text
                                    preferredStyle:UIAlertControllerStyleAlert];
        __weak __typeof(alert) weakAlert = alert;
        for (NSString *title in buttons) {
                UIAlertActionStyle style = UIAlertActionStyleDefault;
                if ([title isEqualToString:[L10n cancelButton]])
                        style = UIAlertActionStyleCancel;
                else if ([title isEqualToString:[L10n deleteButton]])
                        style = UIAlertActionStyleDestructive;
                else if ([title isEqualToString:[L10n archiveButton]])
                        style = UIAlertActionStyleDestructive;

                UIAlertAction *action = [UIAlertAction actionWithTitle:title style:style handler:^(UIAlertAction *action) {
                        if (handler != nil)
                                handler(action, [buttons indexOfObject:action.title]);
                        [weakAlert dismissViewControllerAnimated:YES completion:nil];
                }];
                [alert addAction:action];
        }
        [presenting presentViewController:alert animated:YES completion:nil];
}

这还不是全部。下面是一个使用方法的示例,仅供您参考。在我的情况下,使用了带有搜索功能的,因此呈现控制器可能会有所不同。
- (void) deleteCases:(NSArray *)selectedRows
{
        NSString *text = NSLocalizedStringWithDefaultValue(@"cases.delete.alert.text",
                                                           @"Localizable",  [NSBundle mainBundle],
                                                           @"Deleted cases cannot be restored. Continue with delete?",
                                                           @"Delete alert text");
        NSString *title = NSLocalizedStringWithDefaultValue(@"cases.delete.alert.title",
                                                            @"Localizable",  [NSBundle mainBundle],
                                                            @"Delete cases", @"Detete alert title");
        UIViewController *presenting = self.searchController.active ? self.searchController : self;
        __weak __typeof(presenting) weakPresenting = presenting;
        __weak __typeof(self) weakSelf = self;
        [YourClassName alertWithPresenting:weakPresenting title:title text:text
                                   buttons:@[[L10n deleteButton], [L10n cancelButton]]
                                   handler:^(UIAlertAction *action, NSUInteger index)
        {
                if (action.style == UIAlertActionStyleDestructive) {
                        __typeof(weakSelf) strongSelf = weakSelf;
                        // Perform your actions using @strongSelf
                }
         }];
}

0
你可以使用view.window.rootViewController替代。如果你不在意presenter,这样也是可以的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接