How to customize UIAlertController with UITableView or is there any default control available like this UI in Pages app?
Asked Answered
S

3

15

I would like to implement a UIAlertViewController like this (Reference: Pages and Keynote app):

enter image description here.

I have implemented a custom tableview and presented the view by mimicking the UIAlertViewController. But I cannot achieve a similar UI as above. Is there any default controller available for this?

-(void)share:(id)sender
{
    [self setModalPresentationStyle:UIModalPresentationCurrentContext];

    AlertViewController *renameCntrl = [self.storyboard instantiateViewControllerWithIdentifier:AlertTblViewidentifier];
    renameCntrl.optionViewDelegate = self;
    renameCntrl.providesPresentationContextTransitionStyle = YES;
    renameCntrl.definesPresentationContext = YES;
    [renameCntrl setModalPresentationStyle:UIModalPresentationOverCurrentContext];
    [self presentViewController:renameCntrl animated:YES completion:nil];
}
Salver answered 4/1, 2016 at 14:18 Comment(8)
is there anyway to pop uitableview from uialertviewcontroller.Salver
you want to achieve this functionality through UITableView only..Adaurd
See my answer. I have implemented this multiple times, and it's very easy.Cellar
@LeoNatan Could you share me a sample source code with same GUI look. I tried [alertController setContentViewcontroller] but it shows error as no interface found.Salver
@Salver I'll create a demo project soon.Cellar
@Salver Here you go: dropbox.com/s/0n524x6iilyf57q/CustomAlertController.zip?dl=0Cellar
@LeoNatan Thanku it works grt! ,hope I could add image view in cell to get the same look.Salver
This is the best solution :)Adscititious
P
12

UIAlertController has a private contentViewController property which allows you to set any UIViewController subclass as part of the alert controller. It works well with both action sheet or alert styles. You can mix content view controller with other alert actions.

This is how UIActivityViewController, the Airdrop preview controller, etc. are implemented.

Best practice is to subclass UIAlertController, and in either initWithNibName:bundle: or viewDidLoad, use setValue:forKey: to set the contentViewController property. Don't forget to set the preferredContentSize for your content view controller.

Peradventure answered 29/1, 2016 at 19:22 Comment(7)
"Best practice is to sublclass UIAlertController"... uhhh, no. From the docs: "The UIAlertController class is intended to be used as-is and does not support subclassing."Dryly
@Dryly We are talking about private API here. I can attest it works well.Cellar
I in no way doubt it works. Just would not consider it "best practice." I do not see any reference to the OP talking about private APIs, that is all.Dryly
@Dryly I meant in the context of my answer.Cellar
@LeoNatan, could this code be rejected by Apple?Albrecht
Anything is possible, but if you take the smallest care, like using setValueForKey, I don’t foresee issues with Apple’s automated private API checker.Cellar
With style set to .alert Xcode log this message: A constraint factory method was passed a nil layout anchor. This is not allowed, and may cause confusing exceptions. Break on BOOL _NSLayoutConstraintToNilAnchor(void) to debug. This will be logged only once. This may break in the future.Albrecht
S
2

Adding on to Leo's answer, yes, there is a private property on UIAlertController contentViewController which allows you to set a UIViewController (and it's view) as the content of the UIAlertController.

You can create a private interface to access this property without using KVO or importing a private header like so:

@interface UIAlertController (ContentViewController)
@property (nonatomic, strong) UIViewController * contentViewController;
@end

Then, layout your custom view in your content view controller's view, via Interface Builder or programmatically.

Remember that you also need to override your view controller's preferredContentSize:

- (CGSize)preferredContentSize {
    CGSize contentSize = [super preferredContentSize]; //gets the preferredContentHeight from the view, will be set depending on how much content we have
    return CGSizeMake(contentSize.width, self.view.preferredContentHeight); 
}

Note: rather than overriding the getter, Leo Natan suggests setting the preferredContentSize directly, since it is a property on UIViewController.

You can also override your view controller's view in your subclass as well, if you want.

Set up your alert as your normally would:

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" 
                                                                                    preferredStyle:UIAlertControllerStyleActionSheet];

Set your custom view:

[alertController setContentViewController:[[MyContentViewController alloc] init]];

Add your actions:

[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^{
                       NSLog(@"Cancel Button was pressed");
}];

Present as your normally would:

[self presentViewController:alertController animated:YES completion:nil];

More information on the private APIs of UIAlertController can be found on the iPhone Dev Wiki's article on UIAlertController.

I would also check out the private interfaces on _UIAlertControllerActionView and UIAlertAction, as well as the UIAlertActionViewRepresentation_Internal protocol.

Salzman answered 29/1, 2016 at 19:35 Comment(6)
Do not override preferredContentSize. It's a property, set it.Cellar
@LeoNatan isn't preferredContentSize declared as readonly on UIViewController though?Salzman
Huh? @property(nonatomic) CGSize preferredContentSizeCellar
Ah you're correct, sorry. Was looking at the UIContentContainer protocol by mistake. Will edit my answer to reflect this.Salzman
@Salzman Could you share me a sample source code with same GUI look. I tried [alertController setContentViewcontroller] but it shows error as no interface found.Salver
It seems the setContentViewController is deprecatedEndosmosis
C
0

I think you should use UIAlertController with a preferredStyle set to UIAlertControllerStyleActionSheet.

But if this is not enough start from scratch, from UIWindow and UIViewController with tableView and make any UI you want, there are a lot of custom alertView implementations I'm sure you easily found one for example.

Contend answered 27/1, 2016 at 12:59 Comment(3)
UIAlertcontroller ,is there any way to customize it with images on right side,I already tried UIAlertcontroller but could not achieve the same requirement. Please share me some sample code ,if it can help me.Salver
let storyboard = UIStoryboard(name: "Main", bundle: nil)Albrecht
cell.accessoryViewAlbrecht

© 2022 - 2024 — McMap. All rights reserved.