在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 04:22:14  来源:igfitidea点击:

Loading an "overlay" when running long tasks in iOS

iosswiftuiviewoverlay

提问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)

It will be shown as follows: enter image description here

它将显示如下: 在此处输入图片说明

回答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() } }

demo

演示

回答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 showOverlaycall. And some of the configuration can be passed to the init function, letting only the placement on the showOverlaymethod.

对于像我这样迟到的人,我对@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

回答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:

结果:

Swift OverlayViewController

Swift OverlayViewController

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/

回答by Shourob Datta

Swift 5

斯威夫特 5

showUniversalLoadingView(true, loadingText: "Downloading Data.......")

Uses

用途

showUniversalLoadingView(false)

enter image description here

在此处输入图片说明

showUniversalLoadingView(true) enter image description here

showUniversalLoadingView(true) 在此处输入图片说明

Remove loader

移除装载机

##代码##