快速刷回时,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) }