Reputation: 463
So I have a UIAlertController
which needs to be presented on top of another view controller, so a child view controller. I can get the child view controller to display on top of the parent no problem, but I can't get the alert buttons to respond when I bring this child view controller to the front.
UIAlertController* alert = [AlertHelper createAlertWithTitle:title
message:message
cancelButton:nil
continueButtonText:Ok
continueAction:nil
cancelAction:nil];
alert.view.translatesAutoresizingMaskIntoConstraints = false;
[self addChildViewController:alert];
alert.view.frame = self.view.bounds;
[self.view addSubview:alert.view];
[alert didMoveToParentViewController:self];
[alert.view.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
[alert.view.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES;
Upvotes: 0
Views: 93
Reputation: 77637
UIAlertController
is a specialized controller that makes use of UIAlertAction
.
Worth noting from Apple's docs:
Important
The UIAlertController class is intended to be used as-is and doesn’t support subclassing. The view hierarchy for this class is private and must not be modified.
While you may not be subclassing it (you didn't provide your AlertHelper
code), you're clearly not using it "as-is."
Instead, you probably want to design your own "simulated" alert controller.
Here's a quick example...
AlertHelper.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AlertHelper : NSObject
+ (UIAlertController *)createAlertWithTitle:(NSString *)title
message:(NSString *)message
cancelButton:(NSString *)cancel
continueButtonText:(NSString *)ok
continueAction:(UIAction *)continueAction
cancelAction:(UIAction *)cancelAction;
@end
NS_ASSUME_NONNULL_END
AlertHelper.m
#import "AlertHelper.h"
@implementation AlertHelper
+ (UIViewController *)createAlertWithTitle:(NSString *)title
message:(NSString *)message
cancelButton:(NSString *)cancel
continueButtonText:(NSString *)ok
continueAction:(UIAction *)continueAction
cancelAction:(UIAction *)cancelAction;
{
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.25];
UIView *bkg = [UIView new];
bkg.clipsToBounds = YES;
bkg.backgroundColor = [UIColor systemBackgroundColor];
bkg.layer.cornerRadius = 12.0;
UILabel *titleLabel = [UILabel new];
titleLabel.font = [UIFont systemFontOfSize:17.0 weight:UIFontWeightSemibold];
titleLabel.numberOfLines = 0;
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.text = title;
UILabel *msgLabel = [UILabel new];
msgLabel.font = [UIFont systemFontOfSize:13.0 weight:UIFontWeightRegular];
msgLabel.numberOfLines = 0;
msgLabel.textAlignment = NSTextAlignmentCenter;
msgLabel.text = message;
UIButton *cancelButton = [UIButton systemButtonWithPrimaryAction:cancelAction];
UIButton *okButton = [UIButton systemButtonWithPrimaryAction:continueAction];
cancelButton.layer.borderColor = [UIColor systemBlueColor].CGColor;
okButton.layer.borderColor = [UIColor systemBlueColor].CGColor;
cancelButton.layer.borderWidth = 1.0;
okButton.layer.borderWidth = 1.0;
for (UIView *v in @[bkg, titleLabel, msgLabel, okButton, cancelButton]) {
v.translatesAutoresizingMaskIntoConstraints = NO;
}
for (UIView *v in @[titleLabel, msgLabel, okButton, cancelButton]) {
[bkg addSubview:v];
}
[vc.view addSubview:bkg];
[NSLayoutConstraint activateConstraints:@[
[titleLabel.topAnchor constraintEqualToAnchor:bkg.topAnchor constant:20.0],
[titleLabel.leadingAnchor constraintEqualToAnchor:bkg.leadingAnchor constant:8.0],
[titleLabel.trailingAnchor constraintEqualToAnchor:bkg.trailingAnchor constant:-8.0],
[msgLabel.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:4.0],
[msgLabel.leadingAnchor constraintEqualToAnchor:bkg.leadingAnchor constant:8.0],
[msgLabel.trailingAnchor constraintEqualToAnchor:bkg.trailingAnchor constant:-8.0],
[cancelButton.topAnchor constraintEqualToAnchor:msgLabel.bottomAnchor constant:20.0],
[cancelButton.leadingAnchor constraintEqualToAnchor:bkg.leadingAnchor constant:-1.0],
[okButton.topAnchor constraintEqualToAnchor:cancelButton.topAnchor constant:0.0],
[okButton.trailingAnchor constraintEqualToAnchor:bkg.trailingAnchor constant:1.0],
[cancelButton.bottomAnchor constraintEqualToAnchor:bkg.bottomAnchor constant:1.0],
[cancelButton.trailingAnchor constraintEqualToAnchor:okButton.leadingAnchor constant:1.0],
[cancelButton.widthAnchor constraintEqualToAnchor:okButton.widthAnchor],
[cancelButton.heightAnchor constraintEqualToConstant:40.0],
[okButton.heightAnchor constraintEqualToAnchor:cancelButton.heightAnchor],
[bkg.widthAnchor constraintEqualToConstant:274.0],
[bkg.centerXAnchor constraintEqualToAnchor:vc.view.centerXAnchor],
[bkg.centerYAnchor constraintEqualToAnchor:vc.view.centerYAnchor],
]];
return vc;
}
@end
and an example view controller:
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m
#import "ViewController.h"
#import "AlertHelper.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor systemYellowColor];
UIAction *act = [UIAction actionWithTitle:@"Show Fake Alert VC" image:nil identifier:nil handler:^(UIAction * _Nonnull action) {
[self showFakeAlertVC];
}];
UIButton *btn = [UIButton systemButtonWithPrimaryAction:act];
btn.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];
btn.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:btn];
UILayoutGuide *g = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
[btn.topAnchor constraintEqualToAnchor:g.topAnchor constant:60.0],
[btn.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:80.0],
[btn.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-80.0],
]];
}
- (void)removeFakeAlertVC {
UIViewController *vc;
for (int i = 0; i < [self.childViewControllers count]; i++) {
if ([self.childViewControllers[i].title isEqualToString:@"MyFakeAlertVC"]) {
vc = self.childViewControllers[i];
break;
}
}
if (nil != vc) {
[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
}
}
- (void)showFakeAlertVC {
UIAction *okAction = [UIAction actionWithTitle:@"Continue" image:nil identifier:nil handler:^(UIAction * _Nonnull action) {
// do something because OK / Continue was tapped
NSLog(@"OK tapped!");
[self removeFakeAlertVC];
}];
UIAction *cancelAction = [UIAction actionWithTitle:@"Cancel" image:nil identifier:nil handler:^(UIAction * _Nonnull action) {
// do something because Cancel was tapped
NSLog(@"Cancel tapped!");
[self removeFakeAlertVC];
}];
UIViewController *alert = [AlertHelper createAlertWithTitle:@"Some really long Title that we expect to wrap."
message:@"Some really long Message that we also expect to wrap."
cancelButton:@"Cancel Btn"
continueButtonText:@"Continue Btn"
continueAction:okAction
cancelAction:cancelAction
];
[self addChildViewController:alert];
// we'll use this when we want to remove the
// view and child controller
// in case we have more than one child
alert.title = @"MyFakeAlertVC";
UIView *sv = self.view;
UIView *v = alert.view;
v.translatesAutoresizingMaskIntoConstraints = false;
[sv addSubview:v];
[alert didMoveToParentViewController:self];
[NSLayoutConstraint activateConstraints:@[
[v.topAnchor constraintEqualToAnchor:sv.topAnchor constant:0.0],
[v.leadingAnchor constraintEqualToAnchor:sv.leadingAnchor constant:0.0],
[v.trailingAnchor constraintEqualToAnchor:sv.trailingAnchor constant:0.0],
[v.bottomAnchor constraintEqualToAnchor:sv.bottomAnchor constant:0.0],
]];
}
@end
Output:
Upvotes: 1