UITableViewCell не отменяется при быстром обращении
Теперь я обновил три моих приложения до iOS 7, но во всех трех случаях, несмотря на то, что они не используют какой-либо код, у меня есть проблема, когда пользователь перебирается, чтобы вернуться в контроллер навигации (вместо того, ) быстро, ячейка останется в выбранном состоянии.
В трех приложениях используются пользовательские ячейки, созданные программно, а другой использует пользовательские ячейки, созданные в раскадровке, а третий использует ячейки по умолчанию в очень базовом подклассе UITableView, также в раскадровке. Во всех трех случаях клетки не отделяют себя самостоятельно. Если пользователь медленно проскакивает или обращается к кнопке "Назад", они отменяют выборку как обычно.
Это происходит только в моих приложениях iOS 7, собственные приложения Apple и сторонние приложения, обновленные для iOS 7, все, похоже, ведут себя нормально (хотя и с небольшими различиями в том, как быстро ячейки отключаются).
Должно быть, я что-то делаю неправильно, но я не уверен, что?
Ответы
Ответ 1
Я имею дело с той же проблемой прямо сейчас. UICatalog - пример от Apple, похоже, приносит грязное решение.
Это действительно не радует меня. Как упоминалось ранее, он использует [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:
Когда представление таблицы будет отображаться при первом загрузке, контроллер табличного представления перезагружает данные табличных представлений. Он также очищает его выбор (с анимацией или без нее, в зависимости от запроса) каждый раз, когда отображается представление таблицы. UITableViewController
класс реализует это в методе суперкласса viewWillAppear:
. Вы может отключить это поведение, изменив значение в clearsSelectionOnViewWillAppear
.
Это именно то поведение, которое я ожидаю... но он, похоже, не работает. Ни для тебя, ни для меня. Нам действительно нужно использовать "грязное" решение и сделать это самостоятельно.
Ответ 2
Это сработало лучше для меня:
- (void)viewDidLoad {
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
}
У меня даже получилось намного лучшее снятие заусенцев, когда я медленно возвращался назад.
Ответ 3
Ответ Fabio работает хорошо, но не дает правильного взгляда, если пользователь немного перебирает, а затем меняет свое мнение. Чтобы получить право на этот случай, вам нужно сохранить выбранный путь указателя и reset при необходимости.
- (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
Ответ 4
Это решение анимирует выделение строки вместе с координатором перехода (для отклонения от VC, управляемого пользователем) и повторно применяет выбор, если пользователь отменяет переход. Адаптировано из решения Caleb Davenport в Swift. Проверено только на iOS 9. Протестировано как работа с переходом с помощью пользователя (swipe), так и с нажатием кнопки "Назад" старого стиля.
В подклассе 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];
}
}];
}
}
Ответ 5
После того, как я начал это сегодня, я узнал, что это, видимо, довольно известная проблема с 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];
}
}];
}
}
Ответ 6
Вы можете попробовать установить
self.clearsSelectionOnViewWillAppear = YES;
в UITableViewController или
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:NO];
в viewWillAppear, возможно, перед вызовом [super viewWillAppear: анимированный];
Если ваш UItableView не внутри UITableViewController, вы должны отменить выбор ячейки вручную:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Ответ 7
Я использую
[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];
}
Ответ 8
Простой ответ Swift 3:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if tableView.indexPathForSelectedRow != nil {
self.tableView.deselectRow(at: tableView.indexPathForSelectedRow! as IndexPath, animated: true)
}
}
Ответ 9
Используйте
[tableView deselectRowAtIndexPath:indexPath animated:YES];
код в
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method
Ответ 10
Я нашел очень простое решение этой проблемы, которое просто заставляет поведение по умолчанию работать так, как должно. Я не был удовлетворен решениями с deselectRowAtIndexPath
, так как полученный визуальный эффект несколько отличался.
Все, что вам нужно сделать, чтобы предотвратить это странное поведение, - это перезагрузить таблицу при отображении вида:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.tableView reloadData];
}
Ответ 11
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)
}
}
}
}
Ответ 12
На основе кода 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
Решение Rhult отлично работает на 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
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)
}
})
}
}
Ответ 15
Для быстрого
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
guard let indexPath = tableView.indexPathForSelectedRow else{
return
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}