我现在已将我的三个应用程序更新到iOS 7,但在所有三个应用程序中,尽管它们没有共享任何代码,但我遇到的问题是,如果用户滑动返回导航控制器(而不是点击后面)按钮)快速,单元格将保持其选定状态。
对于这三个应用程序,一个使用以编程方式创建的自定义单元格,另一个使用在故事板中创建的自定义单元格,第三个使用UITableView的一个非常基本的子类中的默认单元格,也在故事板中。在所有三种情况下,细胞不会自行取消选择。如果用户缓慢滑动或按下后退按钮,则会正常取消选择。
这只发生在我的iOS 7应用程序中,Apple自己的应用程序和针对iOS 7升级的第三方应用程序似乎都表现正常(尽管取消选择单元格的速度略有不同)。
一定有些事我做错了,但我不确定是什么?
答案 0 :(得分:54)
这对我来说效果最好:
- (void)viewDidLoad {
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
}
当我慢慢地向后滑动时,我甚至有一个更好的未选择性褪色。
答案 1 :(得分:36)
我现在处理同样的问题。来自Apple的UICatalog样本似乎带来了肮脏的解决方案。
它真的不会让我开心。如前所述,它使用[self.tableView deselectRowAtIndexPath:tableSelection animated:NO];
取消选择当前选定的行。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// this UIViewController is about to re-appear, make sure we remove the current selection in our table view
NSIndexPath *tableSelection = [self.tableView indexPathForSelectedRow];
[self.tableView deselectRowAtIndexPath:tableSelection animated:NO];
// some over view controller could have changed our nav bar tint color, so reset it here
self.navigationController.navigationBar.tintColor = [UIColor darkGrayColor];
}
我不得不提一下示例代码可能不是 iOS 7 iOS 8 iOS 9 iOS 10-ready
让我感到困惑的是UITableViewController Class Reference:
当表格视图即将在第一次加载时出现时, table-view controller重新加载表视图的数据。 它也清除了 它的选择(有或没有动画,取决于要求) 每次显示表格视图时。
UITableViewController
class在超类方法viewWillAppear:
中实现它。您 可以通过更改中的值来禁用此行为clearsSelectionOnViewWillAppear
财产。
这正是我期望的行为......但它似乎不起作用。既不适合你,也不适合我。我们真的必须使用"脏"解决方案并自行完成。
答案 2 :(得分:19)
法比奥的答案效果很好,但如果用户稍微滑动一下然后改变主意就不会给出正确的效果。为了使这种情况正确,您需要保存选定的索引路径并在必要时重置它。
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.savedSelectedIndexPath = nil;
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if (self.savedSelectedIndexPath) {
[self.tableView selectRowAtIndexPath:self.savedSelectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.savedSelectedIndexPath = self.tableView.indexPathForSelectedRow;
if (self.savedSelectedIndexPath) {
[self.tableView deselectRowAtIndexPath:self.savedSelectedIndexPath animated:YES];
}
}
如果使用UITableViewController,请确保禁用内置清除:
self.clearsSelectionOnViewWillAppear = NO;
并添加savedSelectedIndexPath的属性:
@property(strong, nonatomic) NSIndexPath *savedSelectedIndexPath;
如果您需要在几个不同的类中执行此操作,可能需要将其拆分为帮助程序,例如我在此要点中所做的:https://gist.github.com/rhult/46ee6c4e8a862a8e66d4
答案 3 :(得分:9)
此解决方案为行取消选择和转换协调器设置动画(对于用户驱动的VC解除),并在用户取消转换时重新应用选择。改编自Swift中Caleb Davenport的解决方案。仅在iOS 9上测试过。经测试同时使用用户驱动(滑动)转换和旧式" Back"按钮点击。
在UITableViewController
子类中:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Workaround. clearsSelectionOnViewWillAppear is unreliable for user-driven (swipe) VC dismiss
NSIndexPath *indexPath = self.tableView.indexPathForSelectedRow;
if (indexPath && self.transitionCoordinator) {
[self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
[self.tableView deselectRowAtIndexPath:indexPath animated:animated];
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
if ([context isCancelled]) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}];
}
}
答案 4 :(得分:7)
今天遇到这个问题后,我发现这显然是UITableView的一个相当着名的问题,它对交互式导航过渡的支持略有破坏。卡斯特罗背后的人们已经发布了一个出色的分析和解决方案:http://blog.supertop.co/post/80781694515/viewmightappear
我决定使用他们的解决方案,该解决方案也考虑取消过渡:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSIndexPath *selectedRowIndexPath = [self.tableView indexPathForSelectedRow];
if (selectedRowIndexPath) {
[self.tableView deselectRowAtIndexPath:selectedRowIndexPath animated:YES];
[[self transitionCoordinator] notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if ([context isCancelled]) {
[self.tableView selectRowAtIndexPath:selectedRowIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}];
}
}
答案 5 :(得分:5)
您可以尝试设置
self.clearsSelectionOnViewWillAppear = YES;
在UITableViewController或
中[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:NO];
在viewWillAppear中,也许在调用[super viewWillAppear:animated]之前; 如果您的UItableView在UITableViewController中不,您必须手动取消选择单元格:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
答案 6 :(得分:2)
我正在使用
[tableView deselectRowAtIndexPath:indexPath animated:YES];
在方法结束时
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
像这样:
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//doing something according to selected cell...
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
答案 7 :(得分:2)
Simple Swift 3/4答案:
override func viewWillAppear(_ animated: Bool) {
if tableView.indexPathForSelectedRow != nil {
self.tableView.deselectRow(at: tableView.indexPathForSelectedRow! as IndexPath, animated: true)
}
}
答案 8 :(得分:1)
使用
[tableView deselectRowAtIndexPath:indexPath animated:YES];
代码
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method
答案 9 :(得分:1)
我找到了一个非常简单的解决方案,只是让默认行为正常工作。由于产生的视觉效果略有不同,我对涉及deselectRowAtIndexPath
的解决方案并不满意。
为了防止这种奇怪的行为,你需要做的就是在显示视图时重新加载表:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.tableView reloadData];
}
答案 10 :(得分:1)
Codestage answer,在Swift 3中。notifyWhenInteractionEnds
已被弃用。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if let indexPath = self.tableView.indexPathForSelectedRow {
self.tableView.deselectRow(at: indexPath, animated: true)
self.transitionCoordinator?.notifyWhenInteractionChanges { (context) in
if context.isCancelled {
self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
}
}
}
}
答案 11 :(得分:1)
您可能没有调用超级视图的viewWillAppear方法([super viewWillAppear:animated];)。 当您执行此操作,并且UITableViewController的参数clearsSelectionOnViewWillAppear为YES时,将在viewWillAppear上取消选择单元格。
答案 12 :(得分:0)
根据Rhult的代码,我做了一些更改。
此实现允许用户取消向后滑动并仍然保持选中以便将来滑动取消选择动画
@property(strong, nonatomic) NSIndexPath *savedSelectedIndexPath;
- (void)viewDidLoad {
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
}
-(void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.savedSelectedIndexPath = nil;
}
-(void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.savedSelectedIndexPath && ![self.tableView indexPathForSelectedRow]) {
[self.tableView selectRowAtIndexPath:self.savedSelectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
} else {
self.savedSelectedIndexPath = [self.tableView indexPathForSelectedRow];
}
}
答案 13 :(得分:0)
Rhult's solution在iOS 9.2上完美运行。这是Swift中的实现:
在MasterViewController
中声明一个变量以保存IndexPath:
var savedSelectedIndexPath: NSIndexPath?
然后,为了清晰起见,您可以将代码放在扩展名中:
extension MasterViewController {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.savedSelectedIndexPath = nil
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if let indexPath = self.savedSelectedIndexPath {
self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
}
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.savedSelectedIndexPath = tableView.indexPathForSelectedRow
if let indexPath = self.savedSelectedIndexPath {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
}
答案 14 :(得分:0)
Codestage provided by far the best looking answer,所以我决定将其转换为Swift 2。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
let selectedRowIndexPath = self.tableView.indexPathForSelectedRow
if ((selectedRowIndexPath) != nil) {
self.tableView.deselectRowAtIndexPath(selectedRowIndexPath!, animated: true)
self.transitionCoordinator()?.notifyWhenInteractionEndsUsingBlock({ context in
if (context.isCancelled()) {
self.tableView.selectRowAtIndexPath(selectedRowIndexPath, animated: false, scrollPosition: UITableViewScrollPosition.None)
}
})
}
}
答案 15 :(得分:0)
快速
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
guard let indexPath = tableView.indexPathForSelectedRow else{
return
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}