可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
What is example for loading overlay in Swift IOS application when do a long tasks. Example for loading data from remote server.
I googled but not found any answer.
Updated:
Thanks for @Sebastian Dressler this is simple way. I updated my code and it run cool
public class LoadingOverlay{
var overlayView = UIView()
var activityIndicator = UIActivityIndicatorView()
class var shared: LoadingOverlay {
struct Static {
static let instance: LoadingOverlay = LoadingOverlay()
}
return Static.instance
}
public func showOverlay(view: UIView) {
overlayView.frame = CGRectMake(0, 0, 80, 80)
overlayView.center = view.center
overlayView.backgroundColor = UIColor(hex: 0x444444, alpha: 0.7)
overlayView.clipsToBounds = true
overlayView.layer.cornerRadius = 10
activityIndicator.frame = CGRectMake(0, 0, 40, 40)
activityIndicator.activityIndicatorViewStyle = .WhiteLarge
activityIndicator.center = CGPointMake(overlayView.bounds.width / 2, overlayView.bounds.height / 2)
overlayView.addSubview(activityIndicator)
view.addSubview(overlayView)
activityIndicator.startAnimating()
}
public func hideOverlayView() {
activityIndicator.stopAnimating()
overlayView.removeFromSuperview()
}
}
let using:
LoadingOverlay.shared.showOverlay(self.view)
//To to long tasks
LoadingOverlay.shared.hideOverlayView()
回答1:
The above answers add a loading view but it doesn't block click events on the screen also it does not provides overlay for rest of screen.You can achieve it as follows:
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .Alert)
alert.view.tintColor = UIColor.blackColor()
let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRectMake(10, 5, 50, 50)) as UIActivityIndicatorView
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
presentViewController(alert, animated: true, completion: nil)
Swift 3.0
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: true, completion: nil)
Swift 4.0
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.style = UIActivityIndicatorView.Style.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: true, completion: nil)
and you can hide it as follows:
dismiss(animated: false, completion: nil)
It will be shown as follows:
回答2:
Just create yourself an overlay view, which you add to your parent view and remove it once your task is done, e.g. to add it:
var overlay : UIView? // This should be a class variable
[ ... ]
overlay = UIView(frame: view.frame)
overlay!.backgroundColor = UIColor.blackColor()
overlay!.alpha = 0.8
view.addSubview(overlay!)
For removal:
overlay?.removeFromSuperview()
回答3:
Blur background + Activity Indicator, Swift 3 example
extension UIView{
func showBlurLoader(){
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = self.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
activityIndicator.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
activityIndicator.startAnimating()
blurEffectView.contentView.addSubview(activityIndicator)
activityIndicator.center = blurEffectView.contentView.center
self.addSubview(blurEffectView)
}
func removeBluerLoader(){
self.subviews.flatMap { $0 as? UIVisualEffectView }.forEach {
$0.removeFromSuperview()
}
}
}
回答4:
For anyone late like me, I made some modifications to @Sonrobby code. As i understand, @Sonrobby adds the activity to the overlay on every showOverlay
call. And some of the configuration can be passed to the init function, letting only the placement on the showOverlay
method.
I also change the overlay's background to black, since my app it is mostly white.
here is the code :
public class LoadingOverlay{
var overlayView : UIView!
var activityIndicator : UIActivityIndicatorView!
class var shared: LoadingOverlay {
struct Static {
static let instance: LoadingOverlay = LoadingOverlay()
}
return Static.instance
}
init(){
self.overlayView = UIView()
self.activityIndicator = UIActivityIndicatorView()
overlayView.frame = CGRectMake(0, 0, 80, 80)
overlayView.backgroundColor = UIColor(white: 0, alpha: 0.7)
overlayView.clipsToBounds = true
overlayView.layer.cornerRadius = 10
overlayView.layer.zPosition = 1
activityIndicator.frame = CGRectMake(0, 0, 40, 40)
activityIndicator.center = CGPointMake(overlayView.bounds.width / 2, overlayView.bounds.height / 2)
activityIndicator.activityIndicatorViewStyle = .WhiteLarge
overlayView.addSubview(activityIndicator)
}
public func showOverlay(view: UIView) {
overlayView.center = view.center
view.addSubview(overlayView)
activityIndicator.startAnimating()
}
public func hideOverlayView() {
activityIndicator.stopAnimating()
overlayView.removeFromSuperview()
}
}
回答5:
To add on to the answers given, you might run into issues if you are attempting to run the code sometimes. Personally, there was an occasion where showOverlay was not being properly called (because I was trying to segue into a scene, then immediately call this function during viewDidLoad).
If you run into an issue similar to mine, there is one fix to the code and a change in approach I recommend.
FIX: Place both blocks of code as closures to a dispatch_async call, like so:
dispatch_async(dispatch_get_main_queue(),
{ //code });
APPROACH: When calling your code, do a dispatch_after call onto the main queue to delay the call by a few milliseconds.
The reasoning? You're simply asking the UI to do too much during viewDidLoad.
If this appendix to the solution helped, I'd be glad.
-Joel Long
P.S. Solution worked for XCode v6.3.2
回答6:
Updated @sonrobby answer, added a background view and orientation handling via resizing mask... this can be used for simple stuffs
public class LoadingOverlay{
var overlayView = UIView()
var activityIndicator = UIActivityIndicatorView()
var bgView = UIView()
class var shared: LoadingOverlay {
struct Static {
static let instance: LoadingOverlay = LoadingOverlay()
}
return Static.instance
}
public func showOverlay(view: UIView) {
bgView.frame = view.frame
bgView.backgroundColor = UIColor.gray
bgView.addSubview(overlayView)
bgView.autoresizingMask = [.flexibleLeftMargin,.flexibleTopMargin,.flexibleRightMargin,.flexibleBottomMargin,.flexibleHeight, .flexibleWidth]
overlayView.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
overlayView.center = view.center
overlayView.autoresizingMask = [.flexibleLeftMargin,.flexibleTopMargin,.flexibleRightMargin,.flexibleBottomMargin]
overlayView.backgroundColor = UIColor.black
overlayView.clipsToBounds = true
overlayView.layer.cornerRadius = 10
activityIndicator.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
activityIndicator.activityIndicatorViewStyle = .whiteLarge
activityIndicator.center = CGPoint(x: overlayView.bounds.width / 2, y: overlayView.bounds.height / 2)
overlayView.addSubview(activityIndicator)
view.addSubview(bgView)
self.activityIndicator.startAnimating()
}
public func hideOverlayView() {
activityIndicator.stopAnimating()
bgView.removeFromSuperview()
}
}
if you add it to keywindow, it can then go over your nav and tab bars also... something like this
LoadingOverlay.shared.showOverlay(view: UIApplication.shared.keyWindow!)
回答7:
Swift 3.
I used @Lucho's code in his answer below and I changed the overlay background color to clear and added a spinner color.
public class LoadingOverlay {
var overlayView : UIView!
var activityIndicator : UIActivityIndicatorView!
class var shared: LoadingOverlay {
struct Static {
static let instance: LoadingOverlay = LoadingOverlay()
}
return Static.instance
}
init(){
self.overlayView = UIView()
self.activityIndicator = UIActivityIndicatorView()
overlayView.frame = CGRect(0, 0, 80, 80)
overlayView.backgroundColor = .clear
overlayView.clipsToBounds = true
overlayView.layer.cornerRadius = 10
overlayView.layer.zPosition = 1
activityIndicator.frame = CGRect(0, 0, 40, 40)
activityIndicator.center = CGPoint(overlayView.bounds.width / 2, overlayView.bounds.height / 2)
activityIndicator.activityIndicatorViewStyle = .whiteLarge
activityIndicator.color = .gray
overlayView.addSubview(activityIndicator)
}
public func showOverlay(view: UIView) {
overlayView.center = view.center
view.addSubview(overlayView)
activityIndicator.startAnimating()
}
public func hideOverlayView() {
activityIndicator.stopAnimating()
overlayView.removeFromSuperview()
}
}
回答8:
I've created a protocol for presenting your own view controller as an overlay. The usage is very simple:
class ViewController: UIViewController, OverlayHost {
@IBAction func showOverlayButtonPressed() {
showOverlay(type: YourOverlayViewController.self,
fromStoryboardWithName: "Main")
}
}
Result:
Source code: https://github.com/agordeev/OverlayViewController
Related article: https://andreygordeev.com/2017/04/18/overlay-view-controller-protocols-swift/
回答9:
Use ATKit.
Refer:
https://aurvan.github.io/atkit-ios-release/index.html
ATProgressOverlay Class
https://aurvan.github.io/atkit-ios-release/helpbook/Classes/ATProgressOverlay.html
Code:
import ATKit
ATProgressOverlay.sharedInstance.show() // Does not show network activity indicator on status bar.
ATProgressOverlay.sharedInstance.show(isNetworkActivity: true) // Shows network activity indicator on status bar.
Screenshot: