UIRefreshControl 在 UITabBarController 中切换选项卡后卡住
Posted
技术标签:
【中文标题】UIRefreshControl 在 UITabBarController 中切换选项卡后卡住【英文标题】:UIRefreshControl Stuck After Switching Tabs in UITabBarController 【发布时间】:2014-08-12 00:48:07 【问题描述】:我有一个 UITableViewController 作为 UINavigationController 中的根视图控制器,它又是 UITabBarController 中的视图控制器之一。全部连接在 Storyboard 中。
我也在 Storyboard 中为我的表格配置了 UIRefreshControl,通常它在拉动时看起来应该是这样的:
但是,如果我在其他选项卡之间切换一次或两次,它看起来像这样:
它没有旋转或其他任何东西,只是卡在“满”状态,并且一直保持这种状态,直到我完全拉动并触发刷新。
任何想法或建议表示赞赏。
【问题讨论】:
可能是ios本身的bug? 解决方案太多,不起作用。 【参考方案1】:只需添加以下代码,它在所有条件下都能完美运行。
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
guard refreshControl.isRefreshing else return
refreshControl.endRefreshing()
refreshControl.beginRefreshing()
tableView?.contentOffset = CGPoint(x: 0, y: -(refreshControl.bounds.height))
【讨论】:
这是唯一对我有用的解决方案,重要的部分是设置 contentOffset。【参考方案2】:详情
Xcode 版本 10.3 (10G8),Swift 5问题
在选项卡之间切换会冻结活动指示器refreshControl.beginRefreshing(); refreshControl.endRefreshing()
- 将再发送一个请求/拉动刷新事件
解决方案
refreshControl.removeTarget(actionTarget, action: selector, for: .valueChanged)
refreshControl.endRefreshing()
refreshControl.beginRefreshing()
refreshControl.addTarget(actionTarget, action: actionSelector, for: .valueChanged)
完整的解决方案和示例
How to use pull to refresh in Swift?
【讨论】:
【参考方案3】:你可以试试
refreshControl.beginRefreshing()
refreshControl.endRefreshing()
在 viewWillAppear 中,这应该可以工作。
【讨论】:
【参考方案4】:我可以通过在 viewWillDisappear 中放置以下代码来解决这个问题
DispatchQueue.main.async
self.refreshControl.beginRefreshing()
self.refreshControl.endRefreshing()
如果将上述代码放在 viewWillAppear 中,则微调器将在几秒钟内设置动画并关闭,在任何一种情况下,问题都会得到解决,但是,从用户的角度来看,微调器不应该是可见的,所以它是最好把它放在 viewWillDisappear 中。
【讨论】:
【参考方案5】:当刷新控件旋转时,如果您呈现其他控制器并在“结束刷新”之前返回;刷新动画会卡住。
以上答案都不适合我,我不想设置 bool 并在视图控制器的整个生命周期中遵循它。
我的解决方案是将以下代码添加到 viewWillAppear 的末尾。
在对象中;
if (self.refreshControl.isRefreshing)
[self.refreshControl endRefreshing];
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated: true];
[self.refreshControl beginRefreshing];
在斯威夫特中;
if self.refreshControl.isRefreshing
self.refreshControl.endRefreshing
self.tableView.setContentOffset(CGPoint(x: 0, y: self.tableView.contentOffset.y-self.refreshControl.frame.size.height), animated: true)
self.refreshControl.beginRefreshing;
逻辑是;每当它捕捉到刷新控件处于动画状态时,它会在不知道它是否卡住的情况下停止它并重新运行动画。
希望对你有帮助。
【讨论】:
【参考方案6】:Swift 中最好的修复:
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
//fixes bug with refreshControl freezing while switching tabs
if tableView.contentOffset.y < 0
tableView.contentOffset = .zero
【讨论】:
【参考方案7】:在多次遇到同样的问题后,我决定为它创建一个库SwiftPullToRefresh。
如前所述,refreshControl
需要在viewDidDisappear(_:)
上停止并在viewWillAppear(_:)
上启动。
当以编程方式启动refreshControl
动画时,tableView.contentOffset
需要设置为适当的值。
tableView.setContentOffset(CGPoint(x: 0, y: -(refreshControl?.bounds.height ?? 60) - topOffset), animated: true)
var topOffset: CGFloat
if let navigationBar = navigationController?.navigationBar, navigationBar.isTranslucent == true
return navigationBar.bounds.height + UIApplication.shared.statusBarFrame.height
else
return 0
【讨论】:
【参考方案8】:question 中的答案解决了我的问题
基本上在 viewWillAppear 上再次停止和启动微调器
【讨论】:
【参考方案9】:在导航发生之前我无法调用 endRefreshing 来工作,所以我从另一端解决了问题,在 viewWillAppear 上我检查 tableView contentOffset 是否为负数,将 tableView 恢复为 0。
- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:animated];
if (self.tableView.contentOffset.y < 0)
[self.tableView setContentOffset:CGPointZero animated:YES];
【讨论】:
【参考方案10】:希望我能最终帮助解决这个问题:
使用带有 Pull-To-Refresh 控件的 UITableView 存在问题。 这可以通过添加 UITableViewController 轻松解决。
UITableViewController *tableController = [[UITableViewController alloc] init];
tableController.automaticallyAdjustsScrollViewInsets = NO;
[tableController willMoveToParentViewController:self];
[self addChildViewController:tableController];
tableController.tableView = self.containerTableView;
tableController.refreshControl = self.refreshControl;
这样,您只需将 UITableView 包装在控制器中,[self.refreshControl endRefreshing]
将在 viewWillAppear
或 viewWillDisappear
中完全正常工作。在某些情况下,您可能需要同时调用它。
希望这会有所帮助! :)
【讨论】:
【参考方案11】:我想要一些点,喜欢 Albert 的解决方案,但不是他的风格。
- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:animated];
_table.contentOffset = CGPointMake(_table.contentOffset.x, _table.contentOffset.y + 1.0f);
- (void)viewWillDisappear:(BOOL)animated
[super viewWillDisappear:animated];
_table.contentOffset = CGPointMake(_table.contentOffset.x, _table.contentOffset.y - 1.0f);
【讨论】:
【参考方案12】:只需在viewWillDisappear:
中调用endRefreshing
即可为我解决所有问题。
- (void)viewWillDisappear:(BOOL)animated
[super viewWillDisappear:animated];
[self.refreshControl endRefreshing];
在viewWillAppear:
中做同样的事情导致拉表时刷新控件旋转异常。
【讨论】:
视图将消失当我们将应用程序置于后台时不会被调用,在这种情况下加载程序会卡住【参考方案13】:总结并提供完整的解决方案。
问题:
如果 UIRefreshControl 在屏幕转换期间动画,它将保持可见但不会动画。视频https://vid.me/Bkb7
另外,如果拉动刷新动画开始但未完成,然后执行转换,UIRefreshControl 将被隐藏但卡住。视频https://vid.me/Bkb7
解决方案:
在 viewWillAppear 上启动 UIRefreshControl 动画并在 viewDidDisappear 上结束它。保存刷新过程的状态,以了解何时显示 UIRefreshControl。
Bellow 是一个完整的解决方案,它还可以处理正确的动画和简单的拉动刷新动画。
添加到 UITableView 或子类
初始化:
/// Refresh indicator
var refreshControl = UIRefreshControl()
/// Refresh state
var isRefreshing = false
/// Refresh controll update funcion. Set to enable pull to refresh
var refreshControllUpdateFunction: (() -> ())?
/// Prepeares UIRefreshControll. Call from init
func initRefreshControl()
addSubview(refreshControl)
refreshControl.addTarget(self, action: "refreshControllTarget", forControlEvents: .ValueChanged)
refreshControl.beginRefreshing()
isRefreshing = true
Superview 事件处理程序:
/// Call on viewWillApper
func superviewWillApper()
if isRefreshing && !refreshControl.refreshing
startRefreshAnimation()
/// Call on viewDidDisapper
func superviewDidDisappear()
endRefreshAnimation(false, dataFetched: !isRefreshing)
UIRefreshControl 动画处理程序:
/// Presents animating UIRefreshControll
func startRefreshAnimation()
refreshControl.beginRefreshing()
contentOffset = CGPointMake(0, -refreshControl.bounds.size.height)
isRefreshing = true
/// Hides UIRefreshControll and saves state of refresh
func endRefreshAnimation(wasEmpty: Bool, dataFetched: Bool)
refreshControl.endRefreshing()
isRefreshing = !dataFetched
if !wasEmpty
setContentOffset(CGPointZero, animated: true)
else
setContentOffset(CGPointZero, animated: false)
添加
table.isRefreshing = true
到刷新调用的开始。
结果视频https://vid.me/LyuI
【讨论】:
【参考方案14】:我知道这已经非常晚了,但我认为迟到总比没有好。
不幸的是,给定的答案都不适合我。唯一有效的是 viewWillAppear 中这段糟糕的代码:
self.refreshControl = nil;
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(refreshFunction) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
基本上,每次要出现视图时,我都会重新创建 UIRefreshControl。它可以工作,尽管同时给出以下警告:
尝试在刷新控制不空闲时更改它是 强烈劝阻,可能无法正常工作。
我真的很惊讶这仍然是一个问题(现在仍然在 iOS 9 中看到)。希望这可能对其他人有所帮助。
【讨论】:
很好的答案!我在 iOS 9 中仍然看到这个问题。这需要 Apple 在他们的下一个版本中解决。 对我来说也一样。我现在在我的应用程序中看到它。 iOS 10.2 (14C89)。 仍然是 iOS 12.2 唯一合适的解决方案。对于那些考虑在 viewDidAppear 或其他方法上简单地调用“endRefreshing”的人,可以相当快地更改选项卡/视图,这就是这些解决方案不起作用的原因。【参考方案15】:我有一个 collectionView,我确实将它设置为 contentInset。
当按下一些ViewControllers,然后按home键,然后返回并弹回,UIRefreshControl总是在顶部。
最后我用这段代码暂时避开它。 (丑陋但停止它总是显示在顶部)
- (void)viewWillDisappear:(BOOL)animated
[super viewWillDisappear:animated];
[self.refreshControl endRefreshing];
CGPoint currentContentOffset = self.collectionView.contentOffset;
[self.collectionView setContentOffset:CGPointMake(currentContentOffset.x,
currentContentOffset.y - 1.0f)
animated:YES];
- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:animated];
CGPoint currentContentOffset = self.collectionView.contentOffset;
[self.collectionView setContentOffset:CGPointMake(currentContentOffset.x,
currentContentOffset.y + 1.0f)
animated:YES];
【讨论】:
【参考方案16】:以下解决方案可能会对您有所帮助。
CGFloat yTableViewOffset;
- (void)viewDidLoad
yTableViewOffset = kNilOptions;
- (void)viewWillAppear:(BOOL)animated
if(yTableViewOffset != kNilOptions)
CGPoint offset = CGPointMake(tableView.contentOffset.x, yTableViewOffset);
[refreshControl beginRefreshing];
tableView.contentOffset = offset;
- (void)viewWillDisappear:(BOOL)animated
if(refreshControl.isRefreshing)
yTableViewOffset = tableView.contentOffset.y;
[refreshControl endRefreshing];
【讨论】:
【参考方案17】:user2009606 几乎是正确的,我通过调用修复它
[refreshControl endRefreshing];
开启
viewWillAppear:
refreshControl 现在可以在切换选项卡后正常运行,与其状态无关。
【讨论】:
【参考方案18】:我刚刚看到了同样的事情。我最终做的是 viewWillDisappear 上的 endRefreshing ,这至少消除了这个问题。 但是,回到选项卡时,我希望它在我重新启动刷新过程并再次调用 beginRefreshing 时再次开始旋转,但事实并非如此。在我向下钻取导航然后返回的情况下确实如此。
【讨论】:
以上是关于UIRefreshControl 在 UITabBarController 中切换选项卡后卡住的主要内容,如果未能解决你的问题,请参考以下文章
在uitableview中使用UIRefreshControl
UIRefreshControl:刷新时 UITableView '卡住'