UIAlertController 有时会阻止 UIRefreshControl 隐藏
UIAlertController sometimes prevents UIRefreshControl to hide
我在 table 视图上使用 UIRefreshControl
来更新项目。最后,我显示一个 UIAlertController
来通知用户更新已完成,以及更新了多少项目。非常简单,而且在一件事上效果很好。如果我连续多次拉动刷新,有时刷新控件不会被解除,即使在解除警报后也是如此。我需要向上滑动 table 使其消失。
这是我使用的代码,所有 UI 东西都在主线程上完成:
if(refreshControl.refreshing) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self refreshItems];
dispatch_async(dispatch_get_main_queue(), ^{
[refreshControl endRefreshing];
[self.tableView reload];
[self showUpdateInfo];
});
});
}
知道是什么原因造成的吗?
编辑:这就是我在代码中创建刷新控件的方式(在 viewDidLoad
中):
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString: @"Checking for updates…"];
[refreshControl addTarget: self
action: @selector(refreshOutdatedItems)
forControlEvents: UIControlEventValueChanged];
self.refreshControl = refreshControl;
我相信这确实与 tableView 在 UIAlertController 出现之前不向上滚动有关。我试图为 showUpdateInfo 方法设置延迟,这似乎奏效了。我想当用户只拉一次时,需要半秒钟来显示 UIAlertController 检查是否有帮助。
这是我的代码
- (void)refreshOutdatedItems
{
NSLog(@"refresh");
if (self.refreshControl.refreshing) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (double i = 0 ; i < 100000000; i++){
};
dispatch_async(dispatch_get_main_queue(), ^{
[self.refreshControl endRefreshing];
[self performSelector:@selector(showUpdateInfo) withObject:nil afterDelay:0.5];
});
});
}
}
如果有帮助请告诉我。
延迟任意时间不是一个非常干净的解决方案。在我看来,通过加倍到 1000 万来实现延迟也有点 hack。
我最终做的类似于这个伪Swift:
let alert = UIAlertController(...)
present(alert, animated: true) {
refreshControl.endRefreshing()
}
它会延迟对 endRefreshing() 的调用,直到出现警报。
我使用 Swift 3 和 PromiseKit 的实际代码看起来更像这样:
@IBAction func onRefresh() {
Repository.getNewData().then { data in
self.data = data
self.tableView.reloadData()
}.recover { error in
// Return a promise to make sure endRefreshing isn't called until the alert is presented.
return self.presentErrorAlert(message: "Some user-friendly message")
}.always {
self.refreshControl?.endRefreshing()
}
}
private func presentErrorAlert(message: String) -> Promise<Void> {
return Promise<Void> { fulfill, _ in
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true) {
fulfill()
}
}
}
简单地重置table视图的内容偏移:
- (void)endRefreshControl {
[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.bounds.size.height) animated:YES];
[self.refreshControl endRefreshing];
}
当你的任务完成后,调用 [self endRefreshControl];
而不是 [self.refreshControl endRefreshing];
这似乎是 Xcode 中的错误。甚至 Johan Levin 的解决方案有时似乎也挂在 Xcode 9.2.
这不是您要找的东西,但它是一种解决方法:不要使用 UIAlertController。只需将 UIAlertController 中的文本放入 UIRefreshControl,如下所示:
refreshControl?.attributedTitle = NSAttributedString(string: "Pull to reload all reminders", attributes: [NSAttributedStringKey.foregroundColor: UIColor(red: 255.0/255.0, green: 182.0/255.0, blue: 8.0/255.0, alpha: 1.0)])
那些对我有用:
refreshControl.endRefreshing()
tableView.setContentOffset(CGPoint.zero, animated: true)
-- show alert than --
将此扩展程序添加到您的视图控制器:
extension UIViewController {
func showAlert(withTitle title: String, andMessage message: String, completion: (() -> Void)? = nil) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: L10n.General.ok, style: .default, handler: { _ in
self.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: completion)
}
}
然后使用以下代码显示警报。在警报的完成块中,刷新控件停止并将平滑淡出。
showAlert(withTitle: "My Title", andMessage: "There was an error", completion: {
refreshControl.endRefreshing()
})
我在 table 视图上使用 UIRefreshControl
来更新项目。最后,我显示一个 UIAlertController
来通知用户更新已完成,以及更新了多少项目。非常简单,而且在一件事上效果很好。如果我连续多次拉动刷新,有时刷新控件不会被解除,即使在解除警报后也是如此。我需要向上滑动 table 使其消失。
这是我使用的代码,所有 UI 东西都在主线程上完成:
if(refreshControl.refreshing) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self refreshItems];
dispatch_async(dispatch_get_main_queue(), ^{
[refreshControl endRefreshing];
[self.tableView reload];
[self showUpdateInfo];
});
});
}
知道是什么原因造成的吗?
编辑:这就是我在代码中创建刷新控件的方式(在 viewDidLoad
中):
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString: @"Checking for updates…"];
[refreshControl addTarget: self
action: @selector(refreshOutdatedItems)
forControlEvents: UIControlEventValueChanged];
self.refreshControl = refreshControl;
我相信这确实与 tableView 在 UIAlertController 出现之前不向上滚动有关。我试图为 showUpdateInfo 方法设置延迟,这似乎奏效了。我想当用户只拉一次时,需要半秒钟来显示 UIAlertController 检查是否有帮助。 这是我的代码
- (void)refreshOutdatedItems
{
NSLog(@"refresh");
if (self.refreshControl.refreshing) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (double i = 0 ; i < 100000000; i++){
};
dispatch_async(dispatch_get_main_queue(), ^{
[self.refreshControl endRefreshing];
[self performSelector:@selector(showUpdateInfo) withObject:nil afterDelay:0.5];
});
});
}
}
如果有帮助请告诉我。
延迟任意时间不是一个非常干净的解决方案。在我看来,通过加倍到 1000 万来实现延迟也有点 hack。
我最终做的类似于这个伪Swift:
let alert = UIAlertController(...)
present(alert, animated: true) {
refreshControl.endRefreshing()
}
它会延迟对 endRefreshing() 的调用,直到出现警报。
我使用 Swift 3 和 PromiseKit 的实际代码看起来更像这样:
@IBAction func onRefresh() {
Repository.getNewData().then { data in
self.data = data
self.tableView.reloadData()
}.recover { error in
// Return a promise to make sure endRefreshing isn't called until the alert is presented.
return self.presentErrorAlert(message: "Some user-friendly message")
}.always {
self.refreshControl?.endRefreshing()
}
}
private func presentErrorAlert(message: String) -> Promise<Void> {
return Promise<Void> { fulfill, _ in
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true) {
fulfill()
}
}
}
简单地重置table视图的内容偏移:
- (void)endRefreshControl {
[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.bounds.size.height) animated:YES];
[self.refreshControl endRefreshing];
}
当你的任务完成后,调用 [self endRefreshControl];
而不是 [self.refreshControl endRefreshing];
这似乎是 Xcode 中的错误。甚至 Johan Levin 的解决方案有时似乎也挂在 Xcode 9.2.
这不是您要找的东西,但它是一种解决方法:不要使用 UIAlertController。只需将 UIAlertController 中的文本放入 UIRefreshControl,如下所示:
refreshControl?.attributedTitle = NSAttributedString(string: "Pull to reload all reminders", attributes: [NSAttributedStringKey.foregroundColor: UIColor(red: 255.0/255.0, green: 182.0/255.0, blue: 8.0/255.0, alpha: 1.0)])
那些对我有用:
refreshControl.endRefreshing()
tableView.setContentOffset(CGPoint.zero, animated: true)
-- show alert than --
将此扩展程序添加到您的视图控制器:
extension UIViewController {
func showAlert(withTitle title: String, andMessage message: String, completion: (() -> Void)? = nil) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: L10n.General.ok, style: .default, handler: { _ in
self.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: completion)
}
}
然后使用以下代码显示警报。在警报的完成块中,刷新控件停止并将平滑淡出。
showAlert(withTitle: "My Title", andMessage: "There was an error", completion: {
refreshControl.endRefreshing()
})