ios - iOS 问题中的自定义警报 View

标签 ios objective-c uialertview

在我的应用中,我必须创建如下所示的自定义警报 View :

enter image description here

所以我跟着这个tutorial创建自定义警报 View 。我完成了它,但我在以下方法中遇到问题:

- (void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove {
    NSMutableArray *items = [[NSMutableArray alloc]init];

    [items addObject:self.buttonOk];
    [items addObject:self.buttonClose];

    int buttonIndex = (tag == 1);

    if (shouldRemove) {
        [items removeObjectAtIndex:buttonIndex];
    } else {
        if (tag == 1) {
            [items insertObject:self.buttonOk atIndex:buttonIndex];
        } else {
            [items insertObject:self.buttonClose atIndex:buttonIndex];
        }
    }
}

我编辑它而不是教程,因为我不需要按钮的 UIToolBar。当我运行应用程序时,它告诉我无法在 NSMutableArray 中插入 nil 对象,但我不明白哪里出了问题,我希望你能帮助我解决这个问题。

更新 这是我开发的所有类代码:

#import "CustomAlertViewController.h"

#define ANIMATION_DURATION  0.25

@interface CustomAlertViewController ()
- (IBAction)buttonOk:(UIButton *)sender;
- (IBAction)buttonCancel:(UIButton *)sender;
@property (weak, nonatomic) IBOutlet UIButton *buttonClose;
@property (weak, nonatomic) IBOutlet UIButton *buttonOk;

@property (strong, nonatomic) IBOutlet UIView *viewAlert;

-(void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove;

@end

@implementation CustomAlertViewController

- (id)init
{
    self = [super init];
    if (self) {
        [self.viewAlert setFrame:CGRectMake(self.labelAlertView.frame.origin.x,
                                         self.labelAlertView.frame.origin.y,
                                         self.labelAlertView.frame.size.width,
                                         self.viewAlert.frame.size.height)];
        [self.buttonOk setTag:1];
        [self.buttonClose setTag:0];
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)showCustomAlertInView:(UIView *)targetView withMessage:(NSString *)message {
    CGFloat statusBarOffset;

    if (![[UIApplication sharedApplication] isStatusBarHidden]) {
        CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
        if (statusBarSize.width < statusBarSize.height) {
            statusBarOffset = statusBarSize.width;
        } else {
            statusBarOffset = statusBarSize.height;
        }
    } else {
        statusBarOffset = 0.0;
    }
    CGFloat width, height, offsetX, offsetY;

    if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft ||
        [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) {
        width = targetView.frame.size.width;
        height = targetView.frame.size.height;

        offsetX = 0.0;
        offsetY = -statusBarOffset;
    }

    [self.view setFrame:CGRectMake(targetView.frame.origin.x, targetView.frame.origin.y, width, height)];
    [self.view setFrame:CGRectOffset(self.view.frame, offsetX, offsetY)];
    [targetView addSubview:self.view];

    [self.viewAlert setFrame:CGRectMake(0.0, -self.viewAlert.frame.size.height, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];

    [UIView beginAnimations:@"" context:nil];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [self.viewAlert setFrame:CGRectMake(0.0, 0.0, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];
    [UIView commitAnimations];

    [self.labelAlertView setText:@"CIAO"];
}

- (void)removeCustomAlertFromView {
    [UIView beginAnimations:@"" context:nil];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [self.viewAlert setFrame:CGRectMake(0.0, -self.viewAlert.frame.size.height, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];
    [UIView commitAnimations];

    [self.view performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:ANIMATION_DURATION];
}

- (void)removeCustomAlertFromViewInstantly {
    [self.view removeFromSuperview];
}

- (BOOL)isOkayButtonRemoved {
    if (self.buttonOk == nil) {
        return YES;
    } else {
        return NO;
    }
}

- (BOOL)isCancelButtonRemoved {
    if (self.buttonClose == nil) {
        return YES;
    } else {
        return NO;
    }
}

- (void)removeOkayButton:(BOOL)shouldRemove {
    if ([self isOkayButtonRemoved] != shouldRemove) {
        [self addOrRemoveButtonWithTag:1 andActionToPerform:shouldRemove];
    }
}

- (void)removeCancelButton:(BOOL)shouldRemove {
    if ([self isCancelButtonRemoved] != shouldRemove) {
        [self addOrRemoveButtonWithTag:0 andActionToPerform:shouldRemove];
    }
}

- (void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove {
    NSMutableArray *items = [[NSMutableArray alloc]init];

    [items addObject:self.buttonOk];
    [items addObject:self.buttonClose];

    int buttonIndex = (tag == 1);

    if (shouldRemove) {
        [items removeObjectAtIndex:buttonIndex];
    } else {
        if (tag == 1) {
            [items insertObject:self.buttonOk atIndex:buttonIndex];
        } else {
            [items insertObject:self.buttonClose atIndex:buttonIndex];
        }
    }
}

- (IBAction)buttonOk:(UIButton *)sender {
    [self.delegate customAlertOk];
}

- (IBAction)buttonCancel:(UIButton *)sender {
    [self.delegate customAlertCancel];
}
@end

更新 2 我在其中使用 CustomAlertView 的代码:

#import "PromotionsViewController.h"
#import "CustomAlertViewController.h"

@interface PromotionsViewController () <CustomAlertViewControllerDelegate> {
    BOOL isDeletingItem;
}


@property(nonatomic,strong) CustomAlertViewController *customAlert;

- (IBAction)buttonBack:(UIButton *)sender;
@property (weak, nonatomic) IBOutlet UIButton *buttonAlert;
- (IBAction)buttonAlert:(UIButton *)sender;

@end

@implementation PromotionsViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self.buttonAlert setTitle:self.promotionSelected forState:UIControlStateNormal];
    [self.customAlert setDelegate:self];
    isDeletingItem = NO;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)buttonBack:(UIButton *)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)buttonAlert:(UIButton *)sender {
    self.customAlert = [[CustomAlertViewController alloc]init];
    [self.customAlert removeOkayButton:NO];
    [self.customAlert removeCancelButton:NO];
    NSString *message = [NSString stringWithFormat:@"La tua offerta %@ del 20%% è stata convertita in punti IoSi x10", self.promotionSelected];
    [self.customAlert showCustomAlertInView:self.view withMessage:message];
    isDeletingItem = YES;
}

- (void)customAlertOk {
    if (isDeletingItem) {
        [self.customAlert removeCustomAlertFromViewInstantly];
    } else {
        [self.customAlert removeCustomAlertFromView];
    }
}

- (void)customAlertCancel {
    [self.customAlert removeCustomAlertFromView];
    if (isDeletingItem) {
        isDeletingItem = NO;
    }
}

@end

最佳答案

也许您正在调用 addOrRemoveButtonWithTag:andActionToPerform: 时您的 UI 尚未完全创建,因为 UI 元素是异步创建的。因此,如果您在自定义警报 View 实例化之后立即调用此方法,您将崩溃,因为未创建 View 中的按钮。

要解决此问题,您需要仅在将自定义警报添加到 View 层次结构后调用 addOrRemoveButtonWithTag:andActionToPerform:

编辑:

使用您在编辑 2 中给出的示例代码,您调用这些行:

- (IBAction)buttonAlert:(UIButton *)sender {
  self.customAlert = [[CustomAlertViewController alloc]init];
  [self.customAlert removeOkayButton:NO];
  [self.customAlert removeCancelButton:NO];
}

但是当你刚刚实例化CustomAlertViewController时,它的2个按钮还没有创建,所以我建议你添加2个属性hasOkButtonhasCancelButton和你的自定义类的新构造函数,如下所示:

- (instancetype) initWithOk:(BOOL)OkButton AndCancel:(BOOL) CancelButton
{
    if(self = [super init])
    { 
       hasOkButton = OkButton;
       hasCancelButton = CancelButton;
    }
}

-(void)viewWillAppear:(BOOL)animated
{
      [super viewWillAppear:animated];
      // At this time, the custom UI buttons will be created in the UI view hierarchy
      [self removeOkayButton: hasOkButton];
      [self removeOkayButton: hasCancelButton];
}

并且在调用者中,您可以使用以下内容来显示自定义警报 View :

- (IBAction)buttonAlert:(UIButton *)sender {
    self.customAlert = [[CustomAlertViewController alloc] initWithOk:NO AndCancel:NO];
    // ...
}

编辑#2

我在一个真实的项目中尝试了你的解决方案,我通过在调用者中使用这些行使其工作:

- (IBAction)buttonAlert:(UIButton *)sender {
    self.customAlert = [self.storyboard instantiateViewControllerWithIdentifier:@"customAlertView"];
    self.customAlert.hasOK = NO;
    self.customAlert.hasCancel = YES;
    NSString *message = [NSString stringWithFormat:@"La tua offerta %@ del 20%% è stata convertita in punti IoSi x10", self.promotionSelected];
    [self.customAlert showCustomAlertInView:self.view withMessage:message];
    isDeletingItem = YES;
}

CustomAlertViewController 中声明 2 个可见属性 hasOKhasCancel in.h。 并通过添加方法修改您的 .m :

-(void)viewWillAppear:(BOOL)animated
{
    [self removeOkayButton:self.hasOK];
    [self removeCancelButton:self.hasCancel];
}

一定要修改你的 Storyboard(如果符合条件)以这样定义“customAlertView”:

Screen capture of storyboard properties

不要忘记将您的 UIButton 绑定(bind)到 Controller ,这在您的实现中也可能是一个错误:

Bind UIButtons to the controller

希望这对你有帮助:)

关于ios - iOS 问题中的自定义警报 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26181287/

相关文章:

objective-c - 打印调用堆栈的深度

iphone - 在 iTunes 中向我的应用添加评论或星标

ios - 嵌入 Youtube 和 Vimeo 视频

ios - 带有文本字段的 uipickerview 在 textFieldShouldBeginEditing 之后未被调用

iphone - 如何在 iTune Connect 上为我的 iPhone 应用程序设置自动续订应用程序内购买?

objective-c - 如何将 'sender' 发送到 Objective C 中的另一个方法

objective-c - [Obj-C]我如何在使用 NSTask 后做一个 IBAlert?

objective-c - 带有链接备用 ViewController 的 Button 的 UIAlertView

ios - 相机在 iOS 上不工作,getUserMedia 出错

iphone - 防止 VoiceOver 显示位于较大透明 View 下方的 View