我有这段代码:
let x = (self.view.frame.width / 2)
let y = (self.view.frame.height / 2) - (self.navigationController?.navigationBar.frame.height)!
let activityView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
activityView.frame = CGRect(x: 200, y: 120, width: 200, height: 200)
activityView.center = CGPoint(x: x, y: y)
activityView.color = UIColor.blueColor()
activityView.layer.zPosition = 1000
activityView.startAnimating()
activityView.hidesWhenStopped = false
activityView.hidden = false
self.view.addSubview(activityView)
self.view.bringSubviewToFront(activityView)
创建并向我的应用添加指标视图,但它不会在屏幕上显示。
在此和stopAnimating()调用之间有一个(长)JSON请求。
这是在视频预览图层之上,这就是为什么我尝试更改z索引和bringSubviewToFront()
,但它仍然没有显示。
这是我在调试视图层次结构时得到的结果:
指示器视图显示在那里,因此必须将其添加到主视图中。 (蓝色矩形也是一个单独的UIView。)
这是我在应用上看到的内容(没有指示器视图可见!):
我该如何解决这个问题?
答案 0 :(得分:1)
有几个可能的问题:
确保从主线程添加此活动指示器视图。如果此代码在后台线程上运行,请确保将与活动指示器相关的代码发送回主队列。
确保异步执行耗时的JSON请求(例如,使用 // Connects to the first link in the list
console.log("Request to: " + urls[0]);
urls[0] = $.post("php/parser.php",
{
url: urls[0]
},
function(res, state) {
console.log(0 + ": completed");
}
);
for(var y = 0; y < urls.length;/*y++*/) {
$.when(urls[y]).done(function(res) {
// Other calls here
console.log("Doing stuff");
// Continuing with the next link
y++;
if(y < urls.length) {
console.log("Request to: " + urls[y]);
urls[y] = $.post("php/parser.php",
{
url: urls[y]
},
function(res, state) {
console.log(y + ": completed");
}
);
}
}, function(res) {});
}
});
或等效的第三方库)。您必须确保不阻止主线程,因为这会干扰活动指示器视图。
因此,如果您的代码执行的操作与NSURLSession
或NSData(contentsOfURL:)
相同,请将其替换为NSURLConnection.sendSynchronousRequest()
或等效的第三方库。
它可能看起来像:
NSURLSession
你可以像这样使用它:
func performNetworkRequest(request: NSURLRequest, completionHandler: (String?, ErrorType?) -> ()) {
let spinner = startActivityIndicatorView()
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
// regardless of what happens, stop activity indicator view
defer { self.stopActivityIndicatorView(spinner) }
// your parsing code here ...
// when all done, call completion handler
if successful {
completionHandler(..., nil)
} else {
completionHandler(nil, someError)
}
}
task.resume()
}
// I've simplified this a little bit
func startActivityIndicatorView() -> UIActivityIndicatorView {
let x = (self.view.frame.width / 2)
let y = (self.view.frame.height / 2) - (self.navigationController?.navigationBar.frame.height)!
let activityView = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)
activityView.frame = CGRect(x: 200, y: 120, width: 200, height: 200)
activityView.center = CGPoint(x: x, y: y)
activityView.color = .blueColor()
activityView.startAnimating()
self.view.addSubview(activityView)
return activityView
}
func stopActivityIndicatorView(activityView: UIActivityIndicatorView) {
dispatch_async(dispatch_get_main_queue()) {
activityView.removeFromSuperview()
}
}
现在,很明显,完成处理程序的第一个参数将匹配API返回的内容(我使用performNetworkRequest(request) { responseObject, error in
// use responseObject/error here
}
// but not here
,但通常是字典或其他丰富的结构),但希望这说明了基本思路:在主线程上启动活动指示器,异步执行请求和解析,并且只有在请求完成后,删除活动指示器。