I want to add progress bar in swift iOS 8 UIAlertController. Is this possible? Is there any way to subclass UIAlertController and add progres bar and connect some delegate funct
A solution with auto layout:
UIAlertController *alertCtr = [UIAlertController alertControllerWithTitle:@"Test" message:@"50%" preferredStyle:UIAlertControllerStyleAlert];
[alertCtr addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
// Do things
}]];
UIView *alertView = alertCtr.view;
UIProgressView *progressView = [[UIProgressView alloc] initWithFrame:CGRectZero];
progressView.progress = 0.5;
progressView.translatesAutoresizingMaskIntoConstraints = false;
[alertView addSubview:progressView];
NSLayoutConstraint *bottomConstraint = [progressView.bottomAnchor constraintEqualToAnchor:alertView.bottomAnchor];
[bottomConstraint setActive:YES];
bottomConstraint.constant = -45; // How to constraint to Cancel button?
[[progressView.leftAnchor constraintEqualToAnchor:alertView.leftAnchor] setActive:YES];
[[progressView.rightAnchor constraintEqualToAnchor:alertView.rightAnchor] setActive:YES];
[self presentViewController:alertCtr animated:true completion:nil];
My apologies, guys, for using objective c, in this solution, but I thought it might help others, who do not use Swift yet. And, also, you can probably convert this quite easily into Swift. It is more the methodology I wanted to highlight.
I am also not sure whether Apple might reject this solution, but here goes anyway.
Apple states that from iOS7 onwards, UIAlertView should not be subclassed. The view hierarchy for this class is private and must not be modified:
https://developer.apple.com/reference/uikit/uialertview?language=objc
In other words, adding a UIView to a UIAlertView has absolutely no effect.
However, I have a solution that involves adding the UIProgressView above the UIAlertView, but adding the former to the app window. Using the UIView superview.center property, and some slight adjustments, the desired affect can be achieved:
-(void)addProgressBar{
float width = 232;
float height = 5;
self.progbar = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
self.progbar.backgroundColor = [UIColor colorWithWhite:0.75f alpha:1.0f];
[self.progbar setFrame:CGRectMake(0,0,width,height)];
[self.progbar setTrackTintColor:[UIColor colorWithWhite:0.75f alpha:1.0f]];
[self.progbar setProgressTintColor:[UIColor colorWithRed:21.0f/255.0f green:126.0f/255.0f blue:251.0f/255.0f alpha:1.0f]];
self.progbar.alpha = 0.0;
[[UIApplication sharedApplication].keyWindow addSubview:self.progbar];
self.progbar.center = self.progbar.superview.center;
[self.progbar setFrame:CGRectMake(self.progbar.frame.origin.x,self.progbar.frame.origin.y+10,self.progbar.frame.size.width,self.progbar.frame.size.height)];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2.0];
[self.progbar setAlpha:1.0];
[UIView commitAnimations];
}
I add the fade in, to allow the UIAlertView to fully appear first. Then add some other delegate functions to dismiss the UIProgressView, at the correct moments:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(self.alert.cancelButtonIndex == buttonIndex){
[self.progbar removeFromSuperview];
}
}
- (void)alertViewCancel:(UIAlertView *)alertView{
[self.progbar removeFromSuperview];
}
func downloadAlert() {
let alertController = UIAlertController(title: "Title", message: "Loading...", preferredStyle: .Alert)
let progressDownload : UIProgressView = UIProgressView(progressViewStyle: .Default)
progressDownload.setProgress(5.0/10.0, animated: true)
progressDownload.frame = CGRect(x: 10, y: 70, width: 250, height: 0)
alertController.view.addSubview(progressDownload)
presentViewController(alertController, animated: true, completion: nil)
}
If you just need a progressbar you can simply add it as a subview as follows:
Updated for Swift 5:
// Just create your alert as usual:
let alertView = UIAlertController(title: "Please wait", message: "Need to download some files.", preferredStyle: .alert)
alertView.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
// Show it to your users
present(alertView, animated: true, completion: {
// Add your progressbar after alert is shown (and measured)
let margin:CGFloat = 8.0
let rect = CGRect(x: margin, y: 72.0, width: alertView.view.frame.width - margin * 2.0 , height: 2.0)
self.progressView = UIProgressView(frame: rect)
self.progressView!.progress = 0.5
self.progressView!.tintColor = self.view.tintColor
alertView.view.addSubview(self.progressView!)
})
Swift 2.0:
// Just create your alert as usual:
let alertView = UIAlertController(title: "Please wait", message: "Need to download some files.", preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
// Show it to your users
presentViewController(alertView, animated: true, completion: {
// Add your progressbar after alert is shown (and measured)
let margin:CGFloat = 8.0
let rect = CGRectMake(margin, 72.0, alertView.view.frame.width - margin * 2.0 , 2.0)
let progressView = UIProgressView(frame: rect)
progressView.progress = 0.5
progressView.tintColor = UIColor.blueColor()
alertView.view.addSubview(progressView)
})
It's quite difficult to resize the UIAlertController
for bigger content but for a progressbar this should do the trick.