UIKit 状态保存不恢复滚动偏移
Posted
技术标签:
【中文标题】UIKit 状态保存不恢复滚动偏移【英文标题】:UIKit state preservation not restoring scroll offset 【发布时间】:2012-11-28 19:47:04 【问题描述】:我有一个在 ios 6 中使用 UIKit 状态保存的应用程序。我能够保存/恢复视图控制器的状态,即选择了哪个选项卡和导航控制器层次结构,但是我无法恢复我的表视图它是抵消的。我的故事板中有一个用于视图以及视图控制器的恢复标识符,并且视图控制器(表的数据源)实现UIDataSourceModelAssociation
,如下所示:
- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view
TSStatus *status = [self._fetchedResultsController objectAtIndexPath:indexPath];
return status.objectID.URIRepresentation.absoluteString;
- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view
NSURL *statusURL = [NSURL URLWithString:identifier];
NSManagedObjectID *statusID = [[TSDataController sharedController].persistentStoreCoordinator managedObjectIDForURIRepresentation:statusURL];
TSStatus *status = (TSStatus *)[[TSDataController sharedController].mainContext objectWithID:statusID];
return [__fetchedResultsController indexPathForObject:status];
当应用程序进入后台时会调用modelIdentifierForElementAtIndexPath:inView:
,但不会调用modelIdentifierForElementAtIndexPath:inView:
。
【问题讨论】:
我认为您的最后一段是错字? --- “modelIdentifierForElementAtIndexPath:inView: 在应用程序进入后台时被调用,但是 modelIdentifierForElementAtIndexPath:inView: 永远不会被调用。” 【参考方案1】:这不是您问题的真正答案,但我也无法让表格视图恢复其 contentOffset。
我猜这是 iOS 6 中的一个错误,因为文档明确指出 UITableView
恢复其 contentOffset,当 1) 它有一个 restorationIdentifier
2) 视图所属的视图控制器有一个 restorationIdentifier
3)数据源符合UIDataSourceModelAssociation
协议。
您可以在视图控制器中手动恢复 contentOffset 和所选项目:
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
[super encodeRestorableStateWithCoder:coder];
[coder encodeObject:[NSValue valueWithCGPoint:self.tableView.contentOffset] forKey:@"tableView.contentOffset"];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
if (indexPath != nil)
NSString *modelIdentifier = [self modelIdentifierForElementAtIndexPath:indexPath inView:self.tableView];
[coder encodeObject:modelIdentifier forKey:@"tableView.selectedModelIdentifier"];
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
[super decodeRestorableStateWithCoder:coder];
CGPoint contentOffset = [[coder decodeObjectForKey:@"tableView.contentOffset"] CGPointValue];
self.tableView.contentOffset = contentOffset;
NSString *modelIdentifier = [coder decodeObjectForKey:@"tableView.selectedModelIdentifier"];
if (modelIdentifier != nil)
NSIndexPath *indexPath = [self indexPathForElementWithModelIdentifier:modelIdentifier inView:self.tableView];
if (indexPath != nil)
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
我不知道为什么UITableView
不会自动执行此操作,即使文档说明它会执行此操作。如果有人知道答案,请发表评论。
【讨论】:
【参考方案2】:我发现这可以工作,如果 UITableView 也 有一个 restoreIdentifier 集。
但是,如果 UITableViewController 在 UINavigationController 中,它就不起作用。已向 Apple 报告此问题,问题 ID:13536778。此问题似乎同时出现在 iOS 6.0 和 6.1.3 上。
【讨论】:
navigationController 中的表:在 iOS9 中看起来仍然是一个错误【参考方案3】:这是 iOS 6 中的一个错误。
要使用UIDataSourceModelAssociation
协议恢复表视图的状态,您应该在表视图上调用-reloadData
,然后在-indexPathForElementWithModelIdentifier:inView:
中返回有效索引路径,如下所示:
- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view
NSURL *statusURL = [NSURL URLWithString:identifier];
NSManagedObjectID *statusID = [[TSDataController sharedController].persistentStoreCoordinator managedObjectIDForURIRepresentation:statusURL];
TSStatus *status = (TSStatus *)[[TSDataController sharedController].mainContext objectWithID:statusID];
[self.tableView reloadData];
return [__fetchedResultsController indexPathForObject:status];
【讨论】:
这个错误似乎已在 iOS 7 中得到修复。我不再需要调用 reloadData 来恢复表格视图的状态。 indexPathForElementWithModelIdentifier 被多次调用,因此您也一直在重新加载表格【参考方案4】:请参阅 Apple 的状态恢复示例,了解如何实现此目的。神奇的修复发生在decodeRestorableStateWithCoder
方法中,调用reloadData
:
MyTableViewController.m
// this is called when the app is re-launched
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
// important: don't affect our views just yet, we might not visible or we aren't the current
// view controller, save off our ivars and restore our text view in viewWillAppear
//
NSLog(@"MyTableViewController: decodeRestorableStateWithCoder");
[super decodeRestorableStateWithCoder:coder];
self.tableView.editing = [coder decodeBoolForKey:kUnsavedEditStateKey];
[self.tableView reloadData];
请注意,他们对编辑状态进行编码很奇怪,因为编辑在保存开始之前由他们的进入后台通知处理程序结束,因此它总是会恢复不编辑。他们还尝试设置self.tableView.editing
而不是self.editing
,因此编辑按钮不会更新。还要注意关于不影响视图的评论,这首先是奇怪的,因为它们确实会影响视图,并且在解码状态之前调用第二个 viewWillAppear。鉴于这些错误,我不会使用这个示例来调整您的编程技能。
另一个答案是在 indexPathForElementWithModelIdentifier
中重新加载,这不是一个好主意,因为它被多次(至少两次)调用以查找可见和选定对象的各种索引路径。
【讨论】:
以上是关于UIKit 状态保存不恢复滚动偏移的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C++ 中保存和恢复 TensorFlow 图及其状态?
如何在 Android Lollipop 中保存 WebView 状态并恢复它?