UIAlertController background color iOS10 - ios

Code that I wrote for iOS9, worked really well:
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"Select source"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alert.view.backgroundColor = DARK_BLUE;
alert.view.tintColor = NEON_GREEN;
UIView *subview = alert.view.subviews.firstObject;
UIView *alertContentView = subview.subviews.firstObject;
alertContentView.backgroundColor = DARK_BLUE;
alertContentView.layer.cornerRadius = 10;
My point of view is that UIAlertController is inheriting from UIViewController, and UIViewController have property UIView that can be changed. And this is working. Now, that view inherited from UIViewController have it's own subview that is contentView showed as Alert. I can access it as firstObject in array of subviews. Now, why message for sending background color isn't working anymore? Do anyone know some new solution?

For everyone that will bump into the same problem, I've found the solution:
UIAlertController.view contains one subview, that is only container.
That subview contains subview that contains two it's own subviews, one is container, and another is layer for blurring it.
So, it needs for in loop to iterate through that two subviews and change background color of both.
Full code:
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"Select source"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alert.view.tintColor = NEON_GREEN;
UIView *firstSubview = alert.view.subviews.firstObject;
UIView *alertContentView = firstSubview.subviews.firstObject;
for (UIView *subSubView in alertContentView.subviews) { //This is main catch
subSubView.backgroundColor = DARK_BLUE; //Here you change background
}

In Swift 3.0
let FirstSubview = alertController.view.subviews.first
let AlertContentView = FirstSubview?.subviews.first
for subview in (AlertContentView?.subviews)! {
subview.backgroundColor = UIColor.black
subview.layer.cornerRadius = 10
subview.alpha = 1
subview.layer.borderWidth = 1
subview.layer.borderColor = UIColor.yellow.cgColor
}

I use this:
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Alert!"
message:#"Message of alert"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//Your code
}];
[alert addAction:defaultAction];
UIView * topview = alert.view.subviews.firstObject;
UIView * colorView = topview.subviews.firstObject;
colorView.backgroundColor = [UIColor yellowColor];
colorView.layer.cornerRadius = 10;
[self presentViewController:alert animated:YES completion:nil];

Related

uncaught exception 'NSGenericException: application has presented a UIAlertController of style UIAlertControllerStyleActionSheet

I am working on an app which i run on iPhone works well but when i am trying to run on iPad it crashes
Here is my code:
- (void)parseCountryStates:(NSDictionary *)json
{
countryPickerView.hidden = TRUE;
NSDictionary *listing = [json objectForKey:#"country"];
countryArray = [listing allValues];
countryIDArray = [listing allKeys];
[countryPickerView reloadAllComponents];
alertController = [UIAlertController
alertControllerWithTitle:#"Select Service Type"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
int count = (int)[countryPickerView numberOfRowsInComponent:0];
for (int i = 0; i < count; i++)
{
UIAlertAction* button = [UIAlertAction
actionWithTitle:[[countryPickerView delegate] pickerView:countryPickerView titleForRow:i forComponent:0]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
countryField.text = [action title];
countryStr = countryField.text;
if ([countryArray containsObject:countryStr]) {
countryidStr = [countryIDArray objectAtIndex:[countryArray indexOfObject:countryStr]];
NSLog(#"CountryidStr %#",countryidStr);
[self getState];
}
}];
[alertController addAction:button];
}
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action)
{
// UIAlertController will automatically dismiss the view
}];
[alertController addAction:cancel];
[self presentViewController:alertController animated:true completion:nil];
}
I am sharing the crash log of it
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController () of
style UIAlertControllerStyleActionSheet. The modalPresentationStyle of
a UIAlertController with this style is UIModalPresentationPopover. You
must provide location information for this popover through the alert
controller's popoverPresentationController. You must provide either a
sourceView and sourceRect or a barButtonItem. If this information is
not known when you present the alert controller, you may provide it in
the UIPopoverPresentationControllerDelegate method
-prepareForPopoverPresentation.
Add source view and source rect to your alertController.
[[alertController popoverPresentationController] setSourceView:self.view];
[[alertController popoverPresentationController] setSourceRect:CGRectMake(0,0,1,1)];
[[alertController popoverPresentationController] setPermittedArrowDirections:UIPopoverArrowDirectionUp];
[self presentViewController:alertController animated:true completion:nil];
actully on ipad alertcontrollers are not allowed instead you can use pop overs to diaplay kind of alert
Programtically
UIViewController *newViewCont = [[UIViewController alloc] init];
newViewCont.view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 180, 180)];
newViewCont.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:newViewCont animated:YES completion:nil];
UIPopoverPresentationController *pop = [newViewCont popoverPresentationController];
pop.permittedArrowDirections = UIPopoverArrowDirectionAny;
[pop setSourceView:myButton];
[pop setSourceRect:myButton.bounds];
Using storyboards
// grab the view controller we want to show
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:#"Pop"];
// present the controller
// on iPad, this will be a Popover
// on iPhone, this will be an action sheet
controller.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:controller animated:YES completion:nil];
// configure the Popover presentation controller
UIPopoverPresentationController *popController = [controller popoverPresentationController];
popController.permittedArrowDirections = UIPopoverArrowDirectionUp;
popController.delegate = self;
// in case we don't have a bar button as reference
popController.sourceView = self.view;
popController.sourceRect = CGRectMake(30, 50, 10, 10);
dismiss popover
[self dismissViewControllerAnimated:YES completion:nil];
There’s a new protocol called the UIPopoverPresentationControllerDelegate that is called upon dismissal and position change due to rotation or interface changes. We can even prevent a Popover from being dismissed if we wish. Here are the three methods we can implement:
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
// called when a Popover is dismissed
}
- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
// return YES if the Popover should be dismissed
// return NO if the Popover should not be dismissed
return YES;
}
- (void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing _Nonnull *)view {
// called when the Popover changes position
}
Don’t forget to conform to the protocol, and set the delegate to your reacting class.
UIPopovers are not allowed on iPads, but there is a way you can do this as other answers have indicated. Here is a Swift 5.x version.
let ac = UIAlertController(title: "Some title goes here", message: nil, preferredStyle: .actionSheet)
ac.addAction(UIAlertAction(title: "Some button name", style: .default) {
[unowned self] _ in
// stuff to do goes here
self.doSomething()
})
// iPad specific code
ac.popoverPresentationController?.sourceView = self.view
let xOrigin = nil // Replace this with one of the lines at the end
let popoverRect = CGRect(x: xOrigin, y: 0, width: 1, height: 1)
ac.popoverPresentationController?.sourceRect = popoverRect
ac.popoverPresentationController?.permittedArrowDirections = .up
present(ac, animated: true)
Replacing the the let xOrigin = nil line with one of the ones below will control where the popover appears below the navigation bar. You can also change x and y to the proper value in the bounds or frame of a different element if you have control that is below the nav bar on an iPad.
Top Left
let xOrigin = 0
Top Middle
let xOrigin = self.view.bounds.width / 2
Top Right
let xOrigin = self.view.bounds.width
Hope this helps.

how to change UIAlertController cornerRadius

I have created an UIAlertController like this:
UIAlertController deleteView = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleAlert];
deleteView.view.layer.cornerRadius = 100;
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"delete" style:UIAlertActionStyleDefault handler:nil];
[cancelAction setValue:[NSNumber numberWithInteger:NSTextAlignmentLeft] forKey:#"titleTextAlignment"];
[cancelAction setValue:[UIColor blackColor] forKey:#"titleTextColor"];
I want to change the cornerRadius of action label.
I try to get the label like this:
UIView *v1 = deleteView.view.subviews[0];
UIView *v2 = v1.subviews[0];
UIView *v3 = v2.subviews[0];
UIView *v4 = v3.subviews[1].subviews[0].subviews[0];
NSArray *arr = v5.subviews;
NSArray *arr = v4.subviews;
NSLog(#"v4:%#,arr:%#",v4,arr);
I'm getting an empty array
You must set masksToBounds to yes
deleteView.view.layer.cornerRadius = 15;
deleteView.view.layer.masksToBounds = YES;
Following Sathya Baman's answer, add the following line. The background color must match the alertView's current background.
alert.view.backgroundColor = .white
Easy , just do 2 line of code..
deleteView.view.layer.cornerRadius = 100;
deleteView.view.layer.masksToBounds = YES;

iOS popover show twice will crash

I'm using objective-c write about UIAlertControllerStyleActionSheet of UIAlertcontroller.
I want to show alert sheet on the iPhone, and popoverPresentationController on the iPad.
First, I have set the UIPopoverPresentationControllerDelegate delegate.
When I click my button, the pop over have show is correct.
But I click on the screen dismiss the popover. it will show below warning.
[Warning] <_UIPopoverBackgroundVisualEffectView 0x14be52ef0> is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
Now When I click the button show the pop view again.
It will crash show below log.
Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController () of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'
*** First throw call stack:
(0x18d9a41c0 0x18c3dc55c 0x19418a8b0 0x193ac60a8 0x193ac3df4 0x193a08d0c 0x1939faac0 0x19376a22c 0x18d9517dc 0x18d94f40c 0x18d94f89c 0x18d87e048 0x18f2ff198 0x1937e2b50 0x1937dd888 0x10011198c 0x18c8605b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
Have anyone know how to resolve the problem?
My code is below:
#interface ViewController () <...UITextViewDelegate,UITextFieldDelegate...> {
UIAlertController *alertTypeAlertController;
UIAlertAction *alertType1Action;
UIAlertAction *alertType2Action;
UIPopoverPresentationController *popPresenter;
}
- (void)viewDidLoad {
[super viewDidLoad];
alertTypeAlertController = [UIAlertController
alertControllerWithTitle:#"selecte one:"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alertType1Action = [UIAlertAction
actionWithTitle:#"Type1"
style:UIAlertActionStyleDefault
handler:nil];
alertType2Action = [UIAlertAction
actionWithTitle:#"Type2"
style:UIAlertActionStyleDefault
handler:nil];
[alertTypeAlertController addAction: alertType1Action];
[alertTypeAlertController addAction: alertType2Action];
// for ipad
popPresenter = [alertTypeAlertController popoverPresentationController];
popPresenter.permittedArrowDirections = UIPopoverArrowDirectionLeft;
popPresenter.delegate = self;
popPresenter.sourceView = self.theTypeBtn;
popPresenter.sourceRect = CGRectMake(230, 22, 10, 10);
....
}
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
// called when a Popover is dismissed
}
- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
// return YES if the Popover should be dismissed
// return NO if the Popover should not be dismissed
return YES;
}
-(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
enter code here
Thank you very much.
Maybe the UIAlertController and UIPopoverPresentationController objects strongly referenced by the ViewController object which makes
the Popover can't release after you dismiss it.
I later found your problem is that you try to create popPresenter
once in the viewDidLoad method and present it every time you touch
the button,you should create a new one instead,you can move the ViewDidLoad code to a new method,and call it by touch event, fix like this:
- (void)makePopover
{
alertTypeAlertController = [UIAlertController
alertControllerWithTitle:#"selecte one:"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alertType1Action = [UIAlertAction
actionWithTitle:#"Type1"
style:UIAlertActionStyleDefault
handler:nil];
alertType2Action = [UIAlertAction
actionWithTitle:#"Type2"
style:UIAlertActionStyleDefault
handler:nil];
[alertTypeAlertController addAction: alertType1Action];
[alertTypeAlertController addAction: alertType2Action];
// for ipad
popPresenter = [alertTypeAlertController popoverPresentationController];
popPresenter.permittedArrowDirections = UIPopoverArrowDirectionLeft;
popPresenter.canOverlapSourceViewRect = YES; // adding this line
popPresenter.delegate = self;
popPresenter.sourceView = self.theTypeBtn;
popPresenter.sourceRect = CGRectMake(230, 22, 10, 10);
}
- (IBAction)touchButton:(id)sender {
[self makePopover];
[self presentViewController:alertTypeAlertController animated:YES completion:nil];
}
I am just modifying your code, please check if it is working or not.
- (IBAction)actionButton:(UIButton*)sender {
alertTypeAlertController = [UIAlertController
alertControllerWithTitle:#"selecte one:"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alertType1Action = [UIAlertAction
actionWithTitle:#"Type1"
style:UIAlertActionStyleDefault
handler:nil];
alertType2Action = [UIAlertAction
actionWithTitle:#"Type2"
style:UIAlertActionStyleDefault
handler:nil];
[alertTypeAlertController addAction: alertType1Action];
[alertTypeAlertController addAction: alertType2Action];
// for ipad
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
popPresenter = [alertTypeAlertController popoverPresentationController];
popPresenter.permittedArrowDirections = UIPopoverArrowDirectionLeft;
popPresenter.delegate = self;
popPresenter.sourceView = self.theTypeBtn;
popPresenter.sourceRect = CGRectMake(230, 22, 10, 10);
}
[self presentViewController:alertTypeAlertController animated:YES completion:nil];
}

Switch in UIAlert Controller programmatically

I am creating an registration dialog in swift with 3 text field and one Switch and I successfully add three text field two the Alert. The following code shows the same.
let alertController = UIAlertController(title: "Register", message: "", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
// ...
exit(0)
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "Sign UP", style: .Default) { (action) in
// ...
let name0 = alertController.textFields![0] as UITextField
print("Text field: \(name0.text)")
let email1 = alertController.textFields![1] as UITextField
print("Text field: \(email1.text)")
let company2 = alertController.textFields![2] as UITextField
print("Text field: \(company2.text)")
}
alertController.addAction(OKAction)
alertController.addTextFieldWithConfigurationHandler { (textField) in
textField.placeholder = "Name"
textField.keyboardType = .EmailAddress
}
alertController.addTextFieldWithConfigurationHandler { (textField) in
textField.placeholder = "Email"
textField.secureTextEntry = false
}
alertController.addTextFieldWithConfigurationHandler { (textField) in
textField.placeholder = "Company"
textField.secureTextEntry = false
}
self.presentViewController(alertController, animated: true) {
// ...
}
Now I need to add a switch programmatically to the Alert View.We are doing this in Swift2. Is it possible?, i am new to Swift.
This may help you.
Add this method call alertController.view.addSubview(createSwitch()) in above code after alertController.addAction(OKAction).
func createSwitch () -> UISwitch{
let switchControl = UISwitch(frame:CGRectMake(10, 20, 0, 0));
switchControl.on = true
switchControl.setOn(true, animated: false);
switchControl.addTarget(self, action: "switchValueDidChange:", forControlEvents: .ValueChanged);
return switchControl
}
func switchValueDidChange(sender:UISwitch!){
print("Switch Value : \(sender.on))")
}
OutPut :
You can use the RightView of the TextField to add a button. Adding a switch would be nice but the switch does not fit into the TextField height nor can you change the height. To this end you can add a button and use images to make a TickBox.
I have ripped this out of a project so the example image is a little more than below.
In the ViewController header add the TextField Delegate
#interface CustomTableViewController : UITableViewController <UITextFieldDelegate>
Then create your AlertController and add the TextField
// create an alert controller
UIAlertController *alertWithText = [UIAlertController alertControllerWithTitle:title message:body preferredStyle:UIAlertControllerStyleAlert];
// create the actions handled by each button
UIAlertAction *action1 = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction *action2 = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
}];
// add the actions to the alert
[alertWithText addAction:action1];
[alertWithText addAction:action2];
// Establish the weak self reference
__weak typeof(self) weakSelf = self;
[alertWithText addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
// Create button
UIButton *checkbox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkbox setFrame:CGRectMake(2 , 2, 18, 18)]; // Not sure about size
[checkbox setTag:1];
[checkbox addTarget:weakSelf action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
// Setup image for button
[checkbox.imageView setContentMode:UIViewContentModeScaleAspectFit];
[checkbox setImage:[UIImage imageNamed:#"unchecked_checkbox.png"] forState:UIControlStateNormal];
[checkbox setImage:[UIImage imageNamed:#"checked_checkbox.png"] forState:UIControlStateSelected];
[checkbox setImage:[UIImage imageNamed:#"checked_checkbox.png"] forState:UIControlStateHighlighted];
[checkbox setAdjustsImageWhenHighlighted:TRUE];
// Setup the right view in the text field
[textField setClearButtonMode:UITextFieldViewModeAlways];
[textField setRightViewMode:UITextFieldViewModeAlways];
[textField setRightView:checkbox];
// Setup Tag so the textfield can be identified
[textField setTag:-1];
[textField setDelegate:weakSelf];
// Setup textfield
[textField setText:#"Essential"]; // Could be place holder text
}];
[self presentViewController:alertWithText animated:YES completion:nil];
You need to stop the textfield from editing if you purely want that line to be a tick.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if(textField.tag == -1){
return NO;
}
return YES;
}
And your action for your button
-(void)buttonPressed:(UIButton*)sender {
if(sender.selected){
[sender setSelected:FALSE];
} else {
[sender setSelected:TRUE];
}
}
Here are some tick box images too (there are plenty out there, you could even make a switch and try and animate).
This answer is for Objective C. It doesn't use text fields but it does add a UISwitch to a UIAlertController as asked in the main question. I didn't find anything on SO that does exactly this so I'm posting this answer here, rather than posting another question that will get dinged as a duplicate.
This solution is used to enable users to sort a UITableView menu (of a list of projects...)
Thanks to the answer by #technerd, I also made the UISwitch change the text of a UILabel that is also on the same UIAlertController view. It uses KVC (Key-Value Coding) in the layer to pass the UILabel id to the target action when the UISwitch value is changed. (See the setOrderLabelText method in the code)
I was also trying to get around the trick of adding newlines ("\n\n\n\n") to the title or message to artificially move things around, by using constraints.
I used a horizontal UIStackView to hold the UISwitch and it's corresponding UILabel, and then used constraints to set the top anchor of the UIStack and a height constraint on the UIAlertController view to make it big enough to contain the UIStackView and the UIAlertController title.
I don't think it is possible to get the height of the title of the UIAlertController or the height of the action buttons. So I came up with values that worked well on an iPhone X and an iPad 2. As in other SO answers, I will likely come up with a home grown (or find one on GitHub) solution to make this more robust. But since I got this far and got so much from other awesome SO answers, I wanted to give back a bit and share my results.
Here's a screenshot:
And here's the code:
// using KVC, set the label text based on the label tag and toggle the tag
- (void)setOrderLabelText:(UISwitch *)orderSwitch {
UILabel *label = (UILabel *)[orderSwitch.layer valueForKey:#"label"];
label.text = label.tag ? #"Ascending" : #"Descending";
label.tag = label.tag ? 0 : 1;
}
// sort the data based on the user's selections
- (IBAction)sort:(UIButton *)sortButton {
UILabel *label = [[UILabel alloc] init];
label.text = #"Ascending";
label.textColor = UIColor.grayColor;
label.tag = 0;
[label sizeToFit];
UISwitch *orderSwitch = [[UISwitch alloc] init];
orderSwitch.on = YES;
[orderSwitch setOn:YES animated:YES];
// allow the switch to change the text in the label using KVC (key-value coding)
[orderSwitch addTarget:self action:#selector(setOrderLabelText:) forControlEvents:UIControlEventValueChanged];
[orderSwitch.layer setValue:label forKey:#"label"];
UIStackView *stackView = [[UIStackView alloc] init];
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.spacing = 8;
[stackView addArrangedSubview:orderSwitch];
[stackView addArrangedSubview:label];
UIAlertController *alert = [UIAlertController
alertControllerWithTitle: #"Sort Projects By"
message: nil
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *createdButton = [UIAlertAction
actionWithTitle:#"Created"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
[self sortBy:#"created" ascending:orderSwitch.isOn];
}];
UIAlertAction *titleButton = [UIAlertAction
actionWithTitle:#"Title"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
[self sortBy:#"title" ascending:orderSwitch.isOn];
}];
UIAlertAction *subtitleButton = [UIAlertAction
actionWithTitle:#"Subtitle"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
[self sortBy:#"subtitle" ascending:orderSwitch.isOn];
}];
UIAlertAction *cancelButton = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
}];
// add action buttons to the alert
[alert addAction:createdButton];
[alert addAction:titleButton];
[alert addAction:subtitleButton];
[alert addAction:cancelButton];
[alert.view addSubview:stackView];
// center the stack in the alert
[stackView.centerXAnchor constraintEqualToAnchor:alert.view.centerXAnchor].active = YES;
// turn off the autoresizing mask or things get weird
stackView.translatesAutoresizingMaskIntoConstraints = NO;
// use a topAnchor constraint to place the stackview, just below the title
// TODO: figure out how to get the height of the alert title (use 64 for now)
[stackView.topAnchor constraintEqualToAnchor:alert.view.topAnchor constant:64].active = YES;
// layout now to set the view bounds so far - NOTE this does not include the action buttons
[alert.view layoutIfNeeded];
// use a height constraint to make the alert view big enough to hold my stack view
// NOTE: strange, but this must include the header view AND all the action buttons
// TODO: figure out how to get the height of the action buttons (use 52 for each action button for now)
CGFloat height = alert.view.bounds.size.height + alert.actions.count * 52 + stackView.bounds.size.height;
[alert.view.heightAnchor constraintEqualToConstant:height].active = YES;
[self presentViewController:alert animated:YES completion:nil];
}
If you use Recycled Steel's answer above with iOS 13 you can use SF Symbols instead of PNGs. It will solve any scaling issues you might have.
checkbox.imageView.tintColor = UIColor.blackColor;
if (#available(iOS 13.0, *)) {
[checkbox setImage: [UIImage systemImageNamed:#"square"] forState: UIControlStateNormal];
[checkbox setImage: [UIImage systemImageNamed:#"checkmark.square"] forState: UIControlStateHighlighted];
[checkbox setImage: [UIImage systemImageNamed:#"checkmark.square"] forState: UIControlStateSelected];
}

UITextField in UIAlertController (border, backgroundColor)

Here is a screenshot of a UIAlertController. I was just playing around custom fonts and textfield properties but I was unable to accomplish the following:
clear background of the UITextField
no ugly border (black box) as shown below
As I dived more into the code and iOS runtime headers, I was able to modify border and background color but the above issue still remains as those properties belong to a container UITextView. Changing background to clearColor doesn't help.
Has anybody ever played around with this? Not sure if I would ever take my app into production with such ugly text fields.
EDIT (May 13, 15) The answer below by Rory McKinnel is tested for iOS 8 - 8.3 and works just fine. The result is below:
Had some fun with this. The following seems to work. Obviously judging by what was required, it has no future proofing and is a patch away from not working.
I figured this out by walking the view hierarchy in the debugger, from which I noticed a UIVisualEffectView. Removing that seems to give you what you want along with setting the containing view to a clear background. Without removing the visual effect, a clear background shows what is behind the alert view itself for some reason.
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:#"Its Not Pretty!"
message:#"Some times things get ugly!"
preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
textField.text = #"Text: No border and clear 8^)";
}];
[self presentViewController:alertController animated:TRUE completion:^{
}];
for (UIView* textfield in alertController.textfields) {
UIView *container = textField.superview;
UIView *effectView = container.superview.subviews[0];
if (effectView && [effectView class] == [UIVisualEffectView class]){
container.backgroundColor = [UIColor clearColor];
[effectView removeFromSuperview];
}
}
here is the important part in swift:
for textfield: UIView in alertController.textfields {
var container: UIView = textField.superview
var effectView: UIView = container.superview.subviews[0]
container.backgroundColor = UIColor.clearColor()
effectView.removeFromSuperview()
}
Swift 3 clear version
alertController.textFields?.forEach {
$0.superview?.backgroundColor = .clear
$0.superview?.superview?.subviews[0].removeFromSuperview()
}
You can try this.
As you need only clear color to textfield of your alertview.
simply add lines of code after your alertview is created.
UITextField *textField = [alertView textFieldAtIndex:0];
textField.backgroundColor=[UIColor clearColor];
textField.superview.backgroundColor=[UIColor clearColor];
EDIT
for alertviewCoontroller you can add
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.backgroundColor=[UIColor clearColor];
textField.superview.backgroundColor=[UIColor clearColor];
}];
Thanks, revert if any confusion.
You can change the border and background color like this:
let subview = alertController!.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
alertContentView.backgroundColor = UIColor.lightGrayColor()
alertContentView.layer.cornerRadius = 10;
alertContentView.layer.borderWidth = 2;
Swift 2.0 version:
for textField in alert.textFields! {
if let container = textField.superview, let effectView = container.superview?.subviews.first where effectView is UIVisualEffectView {
container.backgroundColor = UIColor.clearColor()
effectView.removeFromSuperview()
}
}
To address the situation as discussed in #Rory McKinnel and #Matthew where the superview are NULL and address modifying presented view:
extension UIAlertController {
override open func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.textFields?.forEach {
$0.superview?.backgroundColor = .color
$0.superview?.superview?.subviews[0].removeFromSuperview()
}
}
}
This is very hacky, so examine it well before using (tested on iOS 8.3):
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"My Alert"
message:#"This is an alert."
preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"This is my placeholder";
textField.backgroundColor = [UIColor colorWithRed:246.0/255.0 green:246.0/255.0 blue:246.0/255.0 alpha:1.0]; // You can change it to whatever color you want
[textField superview].backgroundColor = textField.backgroundColor;
[[textField superview] superview].backgroundColor = [UIColor whiteColor];
}];

Resources