快速刷回时,UITableViewCell不会被取消select

我已经将我的三个应用程序更新到了iOS 7,但是在所有三个应用程序中,尽pipe它们没有共享任何代码,但如果用户在导航控制器(而不是点击后退button)上滑动, ,小区将保持其选定状态。

对于三个应用程序,一个使用以编程方式创build的自定义单元格,另一个使用在故事板中创build的自定义单元格,第三个应用程序在UITableView的一个非常基本的子类中使用默认单元格,同样在故事板中。 在这三种情况下,细胞都不会自行取消select。 如果用户慢慢地滑动,或者点击后退button,则取消select正常。

这只发生在我的iOS 7应用程序,苹果自己的应用程序和iOS 7升级的第三方应用程序似乎都正常行为(虽然细胞被取消select的速度略有不同)。

必须有一些我做错了,但我不知道是什么?

我现在正在处理同样的问题。 来自苹果的UICatalog样本似乎带来了肮脏的解决scheme。

这真的不让我开心。 如前所述,它使用[self.tableView deselectRowAtIndexPath:tableSelection animated:NO]; 取消select当前选定的行。

 - (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就绪


一些让我困惑的东西是UITableViewController类的引用 :

当表视图将在第一次加载时出现时,表视图控制器将重新加载表视图的数据。 每次显示表视图时,它也会清除其select(带或不带animation,具体取决于请求)。 UITableViewController类在超类方法viewWillAppear:实现了这个function。 您可以通过更改clearsSelectionOnViewWillAppear属性中的值来禁用此行为。

这正是我期望的行为…但似乎并不奏效。 既不适合你,也不适合我。 我们真的必须使用“肮脏”的解决scheme,并自己做。

这对我最有效:

 - (void)viewDidLoad { [super viewDidLoad]; self.clearsSelectionOnViewWillAppear = NO; } -(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated]; } 

当我慢慢地回头的时候,我甚至有更好的select。

法比奥的答案效果很好,但是如果用户稍微滑动一点,然后改变主意,就不会给出正确的看法。 为了正确得到这种情况,您需要保存选定的索引path,并在必要时重置它。

 - (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

此解决scheme与转换协调器(用于用户驱动的VC解除)一起animation化取消行,并且如果用户取消转换,则重新应用select。 来自Swift的Caleb Davenport的解决scheme。 仅在iOS 9上进行testing。testing过程中同时使用用户驱动(滑动)转换和旧式“返回”button。

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]; } }]; } } 

今天我遇到这个问题后,我发现这显然是UITableView的一个相当知名的问题,它对交互式导航转换的支持稍微有些破裂。 卡斯特罗背后的人已经发布了一个很好的分析和解决scheme: http : //blog.supertop.co/post/80781694515/viewmightappear

我决定使用他们也考虑取消转换的解决scheme:

 - (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]; } }]; } } 

你可以尝试设置

 self.clearsSelectionOnViewWillAppear = YES; 

在UITableViewController或

 [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:NO]; 

在viewWillAppear,也许在调用之前[super viewWillAppear:animated]; 如果您的UItableView 不在 UITableViewController中,您必须手动取消select这些单元格:

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; } 

我在用着

 [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]; } 

简单的斯威夫特3答案:

 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if tableView.indexPathForSelectedRow != nil { self.tableView.deselectRow(at: tableView.indexPathForSelectedRow! as IndexPath, animated: true) } } 

使用

[tableView deselectRowAtIndexPath:indexPath animated:YES];

代码

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method

我发现这个问题的一个非常简单的解决scheme,只是使默认行为,因为它应该。 我不满意涉及deselectRowAtIndexPath的解决scheme,因为产生的视觉效果略有不同。

所有你需要做的,以防止这种奇怪的行为是当显示视图时重新加载表:

 - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self.tableView reloadData]; } 

CodeStage的答案 ,在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) } } } } 

根据Rhult的代码,我做了一些改变。

这个实现允许用户取消向后滑动并保持select以供将来滑动取消selectanimation

 @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]; } } 

在iOS 9.2上, Rhult的解决scheme非常完美。 这是Swift中的实现:

在你的MasterViewController声明一个variables来保存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) } } } 

Codestage提供了最好看的答案 ,所以我决定把它转换成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) } }) } } 

为了迅速

 override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) guard let indexPath = tableView.indexPathForSelectedRow else{ return } tableView.deselectRowAtIndexPath(indexPath, animated: true) }