加载 webview 时加载动画 stucked/freezed
Loading animation stucked/freezed when webview loads
我加载进度加载动画,当来自 Alamofire 的响应到来时,我使用部分响应来构建完整的 url 我需要在 wkwebview 中加载,然后触发 webview.load( ..).
我的问题是,一旦 webview.load(..) 开始发生,进度加载动画就会卡住并一直卡住,直到我 hide() 它。
我怎样才能让我的动画在 webview 开始加载页面的同时继续移动?
MyViewController.swift
class MyViewController: UIViewController, WKScriptMessageHandler {
var webView: WKWebView?
@IBOutlet weak var webViewContainer: UIView!
var webConfig:WKWebViewConfiguration {
get {
let webCfg:WKWebViewConfiguration = WKWebViewConfiguration()
let userController:WKUserContentController = WKUserContentController()
userController.add(self, name: "mycontroller")
webCfg.userContentController = userController;
return webCfg;
}
}
override func viewDidLoad() {
super.viewDidLoad()
webView = WKWebView (frame: webViewContainer.bounds, configuration: webConfig)
webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
webView?.scrollView.isScrollEnabled = false
webViewContainer.addSubview(webView!)
loadWebview()
}
func loadWebview(){
Loading.shared.show(self.view)
Alamofire.request(MYAPI, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: nil)
.responseJSON { response in
let url = URL(string: "https://path-to-load/\(response.key)")
self.webView!.load(URLRequest(url: url!))
}
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
let message = message.body as! [String:AnyObject]
let event = message["event"] as? String ?? "empty"
switch (event){
case "loading-finished":
DispatchQueue.main.async {
Loading.shared.hide(animated: true)
}
break
default:
break
}
}
}
Loading.swift
public class Loading {
var blurredEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
let imageView = UIImageView(image: UIImage(named: "loading_image"))
class var shared: Loading {
struct LoadingStatic {
static let instance: Loading = Loading()
}
return LoadingStatic.instance
}
init() {
imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
imageView.contentMode = .scaleToFill
blurredEffectView.contentView.addSubview(imageView)
}
public func show(_ view: UIView, inView: Bool = false) {
var window: UIView!
if inView == false, let w = view.window {
window = w
} else {
window = view
}
if blurredEffectView.superview == window {
return
}
let rotation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.toValue = NSNumber(value: Double.pi * 2)
rotation.duration = 1
rotation.isCumulative = true
rotation.repeatCount = Float.greatestFiniteMagnitude
imageView.layer.add(rotation, forKey: "rotationAnimation")
imageView.center = window.center
blurredEffectView.frame = window.bounds
window.addSubview(blurredEffectView)
blurredEffectView.fadeIn()
}
}
可能的解决方案:
1) 当您想要全屏加载时,在应用程序 Window 中进行加载(默认情况下 inview == false),并在 viewDidLoad 中保留 loadWebview()
public func show(_ view: UIView? = nil, inView: Bool = false) {
var window: UIView!
if inView == false, let w = UIApplication.shared.delegate?.window {
window = w
} else {
window = view
}
...
2) 将 loadWebview() 从 viewDidLoad 移动到 viewDidAppear
移至此处的重要部分是 Loading.shared.show(self.view)
。在完成布局之前,我无法为视图的组件设置动画(这恰好发生在 viewDidAppear() 中)。
更多详细信息: viewDidLoad
在 MyViewController 已初始化并已初始化主视图之后但在视图呈现给 UI。这意味着 viewDidLoad 允许我在向用户显示交互之前设置 ViewController 和视图。
尽管这是一个不错且快速的解决方案,但在某些情况下,这可能无法按预期工作,因为 viewDidAppear 可以调用两次, 因此会显示两次加载视图,这将导致在一个奇怪的用户体验中。
我加载进度加载动画,当来自 Alamofire 的响应到来时,我使用部分响应来构建完整的 url 我需要在 wkwebview 中加载,然后触发 webview.load( ..).
我的问题是,一旦 webview.load(..) 开始发生,进度加载动画就会卡住并一直卡住,直到我 hide() 它。
我怎样才能让我的动画在 webview 开始加载页面的同时继续移动?
MyViewController.swift
class MyViewController: UIViewController, WKScriptMessageHandler {
var webView: WKWebView?
@IBOutlet weak var webViewContainer: UIView!
var webConfig:WKWebViewConfiguration {
get {
let webCfg:WKWebViewConfiguration = WKWebViewConfiguration()
let userController:WKUserContentController = WKUserContentController()
userController.add(self, name: "mycontroller")
webCfg.userContentController = userController;
return webCfg;
}
}
override func viewDidLoad() {
super.viewDidLoad()
webView = WKWebView (frame: webViewContainer.bounds, configuration: webConfig)
webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
webView?.scrollView.isScrollEnabled = false
webViewContainer.addSubview(webView!)
loadWebview()
}
func loadWebview(){
Loading.shared.show(self.view)
Alamofire.request(MYAPI, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: nil)
.responseJSON { response in
let url = URL(string: "https://path-to-load/\(response.key)")
self.webView!.load(URLRequest(url: url!))
}
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
let message = message.body as! [String:AnyObject]
let event = message["event"] as? String ?? "empty"
switch (event){
case "loading-finished":
DispatchQueue.main.async {
Loading.shared.hide(animated: true)
}
break
default:
break
}
}
}
Loading.swift
public class Loading {
var blurredEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
let imageView = UIImageView(image: UIImage(named: "loading_image"))
class var shared: Loading {
struct LoadingStatic {
static let instance: Loading = Loading()
}
return LoadingStatic.instance
}
init() {
imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
imageView.contentMode = .scaleToFill
blurredEffectView.contentView.addSubview(imageView)
}
public func show(_ view: UIView, inView: Bool = false) {
var window: UIView!
if inView == false, let w = view.window {
window = w
} else {
window = view
}
if blurredEffectView.superview == window {
return
}
let rotation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.toValue = NSNumber(value: Double.pi * 2)
rotation.duration = 1
rotation.isCumulative = true
rotation.repeatCount = Float.greatestFiniteMagnitude
imageView.layer.add(rotation, forKey: "rotationAnimation")
imageView.center = window.center
blurredEffectView.frame = window.bounds
window.addSubview(blurredEffectView)
blurredEffectView.fadeIn()
}
}
可能的解决方案:
1) 当您想要全屏加载时,在应用程序 Window 中进行加载(默认情况下 inview == false),并在 viewDidLoad 中保留 loadWebview()
public func show(_ view: UIView? = nil, inView: Bool = false) {
var window: UIView!
if inView == false, let w = UIApplication.shared.delegate?.window {
window = w
} else {
window = view
}
...
2) 将 loadWebview() 从 viewDidLoad 移动到 viewDidAppear
移至此处的重要部分是 Loading.shared.show(self.view)
。在完成布局之前,我无法为视图的组件设置动画(这恰好发生在 viewDidAppear() 中)。
更多详细信息: viewDidLoad
在 MyViewController 已初始化并已初始化主视图之后但在视图呈现给 UI。这意味着 viewDidLoad 允许我在向用户显示交互之前设置 ViewController 和视图。
尽管这是一个不错且快速的解决方案,但在某些情况下,这可能无法按预期工作,因为 viewDidAppear 可以调用两次, 因此会显示两次加载视图,这将导致在一个奇怪的用户体验中。