Как отобразить индикатор активности в центре UIAlertController?
В настоящее время у меня UIAlertController
отображается на экране. В представлении предупреждения должны отображаться только 2 элемента, заголовок и UIActivityIndicatorView
в центре оповещения. Ниже приведена функция, отображающая оповещение и его элементы.
func displaySignUpPendingAlert() -> UIAlertController {
//Create the UIAlertController
let pending = UIAlertController(title: "Creating New User", message: nil, preferredStyle: .Alert)
//Create the activity indicator to display in it.
let indicator = UIActivityIndicatorView(frame: CGRectMake(pending.view.frame.width / 2.0, pending.view.frame.height / 2.0, 20.0, 20.0))
indicator.center = CGPointMake(pending.view.frame.width / 2.0, pending.view.frame.height / 2.0)
//Add the activity indicator to the alert's view
pending.view.addSubview(indicator)
//Start animating
indicator.startAnimating()
self.presentViewController(pending, animated: true, completion: nil)
return pending
}
однако индикатор активности не отображается в центре представления, на самом деле он отображается в правом нижнем углу экрана, вдали от представления. В чем причина этого?
EDIT: я понимаю, что могу номера hardcode для позиции индикатора, но я хочу, чтобы предупреждение работало на нескольких устройствах с несколькими размерами экрана и ориентациями.
12 ответов
обязательно установите свойство frame при создании представления.
func displaySignUpPendingAlert() -> UIAlertController {
//create an alert controller
let pending = UIAlertController(title: "Creating New User", message: nil, preferredStyle: .Alert)
//create an activity indicator
let indicator = UIActivityIndicatorView(frame: pending.view.bounds)
indicator.autoresizingMask = [.flexibleWidth, .flexibleHeight]
//add the activity indicator as a subview of the alert controller's view
pending.view.addSubview(indicator)
indicator.isUserInteractionEnabled = false // required otherwise if there buttons in the UIAlertController you will not be able to press them
indicator.startAnimating()
self.presentViewController(pending, animated: true, completion: nil)
return pending
}
к @62Shark:
let pending = UIAlertController(title: "Creating New User", message: nil, preferredStyle: .Alert)
let indicator = UIActivityIndicatorView()
indicator.setTranslatesAutoresizingMaskIntoConstraints(false)
pending.view.addSubview(indicator)
let views = ["pending" : pending.view, "indicator" : indicator]
var constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:[indicator]-(-50)-|", options: nil, metrics: nil, views: views)
constraints += NSLayoutConstraint.constraintsWithVisualFormat("H:|[indicator]|", options: nil, metrics: nil, views: views)
pending.view.addConstraints(constraints)
indicator.userInteractionEnabled = false
indicator.startAnimating()
self.presentViewController(pending, animated: true, completion: nil)
я преобразовал ответ в Objective C, если кто-то заинтересован:
UIAlertController *pending = [UIAlertController alertControllerWithTitle:nil
message:@"Please wait...\n\n"
preferredStyle:UIAlertControllerStyleAlert];
UIActivityIndicatorView* indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.color = [UIColor blackColor];
indicator.translatesAutoresizingMaskIntoConstraints=NO;
[pending.view addSubview:indicator];
NSDictionary * views = @{@"pending" : pending.view, @"indicator" : indicator};
NSArray * constraintsVertical = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[indicator]-(20)-|" options:0 metrics:nil views:views];
NSArray * constraintsHorizontal = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[indicator]|" options:0 metrics:nil views:views];
NSArray * constraints = [constraintsVertical arrayByAddingObjectsFromArray:constraintsHorizontal];
[pending.view addConstraints:constraints];
[indicator setUserInteractionEnabled:NO];
[indicator startAnimating];
[self presentViewController:pending animated:YES completion:nil];
Ура
tl; dr
все остальные ответы отключены:) см. документацию:
важно
класс UIAlertController предназначен для использования как есть, так и нет поддержка подклассов. The посмотреть иерархию для данного класса является частным и не должно быть изменено.
для таких, как я, кто предпочитает UIActivityIndicatorView
выровнено слева от UIAlertController.title
, Это мое решение в Свифт работает для всех устройств:
let alert = UIAlertController(title: NSLocalizedString("Authenticating...", comment: "Authenticating"), message: nil, preferredStyle: .Alert);
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
activityIndicator.frame = activityIndicator.frame.rectByOffsetting(dx: 8, dy: (alert.view.bounds.height - activityIndicator.frame.height)/2);
activityIndicator.autoresizingMask = .FlexibleRightMargin | .FlexibleTopMargin | .FlexibleBottomMargin
activityIndicator.color = themeManager().currentTheme.navigationBarTintColor;
activityIndicator.startAnimating();
alert.view.addSubview(activityIndicator);
self.presentViewController(progressAlert, animated: true, completion: nil);
однако, чтобы выровнять UIActivityIndicatorView
в центре просмотра вы можете изменить следующим образом:
activityIndicator.center = CGPoint(x: (alert.view.bounds.width)/2, y: (alert.view.bounds.height)/2)
activityIndicator.autoresizingMask = .FlexibleLeftMargin | .FlexibleRightMargin | .FlexibleTopMargin | .FlexibleBottomMargin
Apple не поощряет прямой подкласс UIAlertController, поэтому я сделал класс, который отображает UIAlertController с центрированным UIActivityIndicator и обрабатывает условие отмены с протоколом класса.
import Foundation
import UIKit
protocol BusyAlertDelegate {
func didCancelBusyAlert()
}
class BusyAlert {
var busyAlertController: UIAlertController?
var presentingViewController: UIViewController?
var activityIndicator: UIActivityIndicatorView?
var delegate:BusyAlertDelegate?
init (title:String, message:String, presentingViewController: UIViewController) {
busyAlertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
busyAlertController!.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel Button"), style: UIAlertActionStyle.Cancel, handler:{(alert: UIAlertAction!) in
delegate?.didCancelBusyAlert()
}))
self.presentingViewController = presentingViewController
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
busyAlertController!.view.addSubview(activityIndicator!)
}
func display() {
dispatch_async(dispatch_get_main_queue(), {
self.presentingViewController!.presentViewController(self.busyAlertController!, animated: true, completion: {
self.activityIndicator!.translatesAutoresizingMaskIntoConstraints = false
self.busyAlertController!.view.addConstraint(NSLayoutConstraint(item: self.activityIndicator!, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self.busyAlertController!.view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0))
self.busyAlertController!.view.addConstraint(NSLayoutConstraint(item: self.activityIndicator!, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self.busyAlertController!.view, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
self.activityIndicator!.startAnimating()
})
})
}
func dismiss() {
dispatch_async(dispatch_get_main_queue(), {
self.busyAlertController?.dismissViewControllerAnimated(true, completion: nil)
})
}
}
Я рекомендую использовать lazy var для инициализации класса.
lazy var busyAlertController: BusyAlert = {
let busyAlert = BusyAlert(title: "Lengthy Task", message: "Please wait...", presentingViewController: self)
busyAlert.delegate = self
return busyAlert
}()
вот ссылка на пример кода:https://github.com/cgilleeny/BusyAlertExample.git
в swift:
activityIndicator.center = self.view.center
Если у вас есть панель инструментов или navController, вы можете переместить точку, но в противном случае центр является центром...
Если у вас все еще есть проблемы, возможно этой учебник поможет. Если вы пытаетесь центрировать его в контроллере представления таблицы, этой ответ может помочь.
Я должен реализовать NSLayoutConstraint
s, чтобы поставить UIActivityIndicatorView
в центре UIAlertController
Для Swift 3:
let loadingAlertController = UIAlertController(title: "Loading", message: nil, preferredStyle: .alert)
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
loadingAlertController.view.addSubview(activityIndicator)
let xConstraint = NSLayoutConstraint(item: activityIndicator, attribute: .centerX, relatedBy: .equal, toItem: loadingAlertController.view, attribute: .centerX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: activityIndicator, attribute: .centerY, relatedBy: .equal, toItem: loadingAlertController.view, attribute: .centerY, multiplier: 1.4, constant: 0)
NSLayoutConstraint.activate([ xConstraint, yConstraint])
activityIndicator.isUserInteractionEnabled = false
activityIndicator.startAnimating()
let height: NSLayoutConstraint = NSLayoutConstraint(item: loadingAlertController.view, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 80)
loadingAlertController.view.addConstraint(height);
self.present(loadingAlertController, animated: true, completion: nil)
попробуйте это:
activityView.center = CGPointMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height / 2.0)
Также вам нужно будет проверить ландшафтный режим и обратную ширину и высоту.
if(landscapeMode)activityView.center = CGPointMake(self.view.bounds.size.height/2.0, self.view.bounds.size.width / 2.0)
может быть, вы можете получить представление предупреждений позиции?
alert.view.frame.origin.x
alert.view.frame.origin.y
и использовать это, чтобы разместить представление активности динамически ie с переменными?
конечно, вы также можете получить размер деления на 2 и добавить, что так, что его центр, а также.
alert.view.frame.size.height
alert.view.frame.size.width
У меня была такая же проблема и через позиционирование кадра не работало для меня. Ответ Yimin Lin был очень близок для меня, но я просто хотел представить альтернативу, используя ограничения в невизуальном формате:
//...
indicator.setTranslatesAutoresizingMaskIntoConstraints(false)
alert.view.addSubview(indicator)
alert.view.addConstraint(NSLayoutConstraint(item: indicator, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: alert.view, attribute: attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0))
alert.view.addConstraint(NSLayoutConstraint(item: indicator, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: alert.view, attribute: attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
//...
преобразованный ответ @petesalt в Swift 3:
let pending = UIAlertController(title: "Saving, please wait...", message: nil, preferredStyle: .alert)
let indicator = UIActivityIndicatorView()
indicator.translatesAutoresizingMaskIntoConstraints = false
pending.view.addSubview(indicator)
let views = ["pending" : pending.view, "indicator" : indicator]
var constraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[indicator]-(-50)-|", options: NSLayoutFormatOptions.alignAllCenterY, metrics: nil, views: views)
constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[indicator]|", options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: views)
pending.view.addConstraints(constraints)
indicator.isUserInteractionEnabled = false
indicator.startAnimating()
self.present(pending, animated: true, completion: nil)
Как насчет этого способа для Swift 3 и выше:
func showActivityIndiactorViewController(title: String) -> UIAlertController {
let pending = UIAlertController(title: "", message: nil, preferredStyle: .alert)
let heightConstraint:NSLayoutConstraint = NSLayoutConstraint(item: pending.view, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: self.view.frame.height * 0.10)
pending.view.addConstraint(heightConstraint)
let label = UILabel()
label.text = title
label.textColor = UIColor.black
label.sizeToFit()
let space = UIView(frame: CGRect(x: 0, y: 0, width: 8, height: 8))
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
indicator.isUserInteractionEnabled = false
indicator.startAnimating()
let width = Int(label.frame.size.width + indicator.frame.size.width + space.frame.size.width)
let view = UIStackView(arrangedSubviews: [indicator, space, label])
view.axis = .horizontal
view.frame = CGRect(x: 20, y: 0, width: width, height: Int(heightConstraint.constant))
pending.view.addSubview(view)
let widthConstraint:NSLayoutConstraint = NSLayoutConstraint(item: pending.view, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.greaterThanOrEqual, toItem: view, attribute: NSLayoutAttribute.width, multiplier: 1, constant: CGFloat(width))
pending.view.addConstraint(widthConstraint)
self.present(pending, animated: true, completion: nil)
return pending
}