在 iOS 中运行长任务时加载“覆盖”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27960556/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Loading an "overlay" when running long tasks in iOS
提问by Sonrobby
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.
在执行长任务时在 Swift IOS 应用程序中加载叠加层的示例是什么。从远程服务器加载数据的示例。我用谷歌搜索但没有找到任何答案。
Updated:
更新:
Thanks for @Sebastian Dressler this is simple way. I updated my code and it run cool
感谢@Sebastian Dressler,这是一个简单的方法。我更新了我的代码,它运行起来很酷
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()
回答by Ajinkya Patil
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
斯威夫特 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 and newer
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)
回答by Sebastian Dressler
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()
回答by Maor
Blur background + Activity Indicator, Swift 5 example
模糊背景 + 活动指示器,Swift 5 示例
extension UIView {
func showBlurLoader() {
let blurLoader = BlurLoader(frame: frame)
self.addSubview(blurLoader)
}
func removeBluerLoader() {
if let blurLoader = subviews.first(where: { 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()
}
}
is BlurLoader }) {
blurLoader.removeFromSuperview()
}
}
}
class BlurLoader: UIView {
var blurEffectView: UIVisualEffectView?
override init(frame: CGRect) {
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = frame
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.blurEffectView = blurEffectView
super.init(frame: frame)
addSubview(blurEffectView)
addLoader()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func addLoader() {
guard let blurEffectView = blurEffectView else { return }
let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
activityIndicator.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
blurEffectView.contentView.addSubview(activityIndicator)
activityIndicator.center = blurEffectView.contentView.center
activityIndicator.startAnimating()
}
}
回答by Lucho
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.
对于像我这样迟到的人,我对@Sonrobby 代码进行了一些修改。据我了解,@Sonrobby 在每次showOverlay
通话时都会将活动添加到叠加层中。并且可以将一些配置传递给 init 函数,只让放置在showOverlay
方法上。
I also change the overlay's background to black, since my app it is mostly white.
我还将叠加层的背景更改为黑色,因为我的应用程序大部分是白色的。
here is the 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.
回答by Rupendra
Use ATKit.
使用 ATKit。
Refer: https://aurvan.github.io/atkit-ios-release/index.html
参考:https: //aurvan.github.io/atkit-ios-release/index.html
ATProgressOverlay Class https://aurvan.github.io/atkit-ios-release/helpbook/Classes/ATProgressOverlay.html
ATProgressOverlay 类 https://aurvan.github.io/atkit-ios-release/helpbook/Classes/ATProgressOverlay.html
Code:
代码:
dispatch_async(dispatch_get_main_queue(),
{ //code });
Screenshot:
截屏:
回答by Joel Long
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).
要补充给出的答案,如果您有时尝试运行代码,您可能会遇到问题。就个人而言,有一次没有正确调用 showOverlay(因为我试图进入场景,然后在 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 调用中,如下所示:
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()
}
}
APPROACH: When calling your code, do a dispatch_after call onto the main queueto delay the call by a few milliseconds.
方法:调用代码时,对主队列执行dispatch_after 调用以将调用延迟几毫秒。
The reasoning? You're simply asking the UI to do too much during viewDidLoad.
推理?您只是在 viewDidLoad 期间要求 UI 做太多事情。
If this appendix to the solution helped, I'd be glad.
如果解决方案的这个附录有帮助,我会很高兴。
-Joel Long
-乔尔·朗
P.S. Solution worked for XCode v6.3.2
PS 解决方案适用于 XCode v6.3.2
回答by anoop4real
Updated @sonrobby answer, added a background view and orientation handling via resizing mask... this can be used for simple stuffs
更新了@sonrobby 答案,通过调整遮罩大小添加了背景视图和方向处理......这可以用于简单的东西
LoadingOverlay.shared.showOverlay(view: UIApplication.shared.keyWindow!)
if you add it to keywindow, it can then go over your nav and tab bars also... something like this
如果你将它添加到 keywindow,它也可以通过你的导航栏和标签栏......像这样
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()
}
}
回答by markhorrocks
Swift 3.
斯威夫特 3.
I used @Lucho's code in his answer below and I changed the overlay background color to clear and added a spinner color.
我在下面的回答中使用了@Lucho 的代码,并将叠加背景颜色更改为清除并添加了微调颜色。
class ViewController: UIViewController, OverlayHost {
@IBAction func showOverlayButtonPressed() {
showOverlay(type: YourOverlayViewController.self,
fromStoryboardWithName: "Main")
}
}
回答by Andrey Gordeev
I've created a protocol for presenting your own view controller as an overlay. The usage is very simple:
我已经创建了一个协议,用于将您自己的视图控制器呈现为叠加层。用法很简单:
class func showUniversalLoadingView(_ show: Bool, loadingText : String = "") {
let existingView = UIApplication.shared.windows[0].viewWithTag(1200)
if show {
if existingView != nil {
return
}
let loadingView = self.makeLoadingView(withFrame: UIScreen.main.bounds, loadingText: loadingText)
loadingView?.tag = 1200
UIApplication.shared.windows[0].addSubview(loadingView!)
} else {
existingView?.removeFromSuperview()
}
}
class func makeLoadingView(withFrame frame: CGRect, loadingText text: String?) -> UIView? {
let loadingView = UIView(frame: frame)
loadingView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
let activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
//activityIndicator.backgroundColor = UIColor(red:0.16, green:0.17, blue:0.21, alpha:1)
activityIndicator.layer.cornerRadius = 6
activityIndicator.center = loadingView.center
activityIndicator.hidesWhenStopped = true
activityIndicator.style = .white
activityIndicator.startAnimating()
activityIndicator.tag = 100 // 100 for example
loadingView.addSubview(activityIndicator)
if !text!.isEmpty {
let lbl = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 30))
let cpoint = CGPoint(x: activityIndicator.frame.origin.x + activityIndicator.frame.size.width / 2, y: activityIndicator.frame.origin.y + 80)
lbl.center = cpoint
lbl.textColor = UIColor.white
lbl.textAlignment = .center
lbl.text = text
lbl.tag = 1234
loadingView.addSubview(lbl)
}
return loadingView
}
Result:
结果:
Source code: https://github.com/agordeev/OverlayViewController
源代码:https: //github.com/agordeev/OverlayViewController
Related article: https://andreygordeev.com/2017/04/18/overlay-view-controller-protocols-swift/
相关文章:https: //andreygordeev.com/2017/04/18/overlay-view-controller-protocols-swift/