Почему UITableViewCell остается выделенным?

145

Что может вызвать выделение ячейки табличного представления после прикосновения? Я щелкаю ячейку и вижу, что она остается подсвеченной, когда отображается подробный вид. После того, как подробный вид извлечен, ячейка все еще подсвечивается.

4thSpace
источник

Ответы:

262

По вашему didSelectRowAtIndexPathнеобходимо позвонить, deselectRowAtIndexPathчтобы отменить выбор ячейки.

Так что, что бы вы ни делали в didSelectRowAtIndexPathсебе, просто вызовите deselectRowAtIndexPathэто.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 // Do some stuff when the row is selected
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
}
paulthenerd
источник
11
Я предпочитаю вызывать deselectRowAtIndexPathв моем viewDidAppear, если при выборе строки открывается новое представление.
notnoop
5
На самом деле это не то место, где его можно назвать, на самом деле ... попробуйте использовать приложение Apple с таблицами (контакты - это хорошо), и вы увидите, что после выхода на новый экран по возвращении ячейка все еще подсвечивается кратко перед отменой выбора. Теоретически я думаю, что вам не нужно делать никакой дополнительной работы, чтобы сразу отменить выделение, поэтому код в viewDidAppear не понадобится ...
Кендалл Хельмстеттер Гелнер
6
@Kendall, @ 4thSpace: Возможно, мой последний комментарий сбил с толку того, о ком я говорил, извиняюсь за это. UITableViewController вызывает -deselectRowAtIndexPath:animated:метод для своего свойства tableView из -viewDidAppear. Однако, если у вас есть табличное представление в подклассе UIViewController, вам следует позвонить -deselectRowAtIndexPath:animated:от -viewDidAppearсебя. :)
Даниэль Тулл
5
В моем подклассе UITableViewController это было переопределением, -viewWillAppear:которое сломало его. Добавление звонка, чтобы [super viewWillAppear:animated]он снова заработал.
Бен Чалленор
5
Так как 3.2, автоматическое поведение , если происходит отмена выбора вашего UITableViewController«S clearsSelectionOnViewWillAppearсвойство имеет значение YES(значение по умолчанию), и вы не предотвратили [super viewWillAppear]от призыва.
Дефрагментирован
62

Самый чистый способ сделать это на viewWillAppear:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // Unselect the selected row if any
    NSIndexPath*    selection = [self.tableView indexPathForSelectedRow];
    if (selection) {
        [self.tableView deselectRowAtIndexPath:selection animated:YES];
    }
}

Таким образом, у вас есть анимация затухания выделения при возвращении в контроллер, как и должно быть.

Взято с http://forums.macrumors.com/showthread.php?t=577677

Swift версия

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // deselect the selected row if any
    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRowNotNill = selectedRow {
        tableView.deselectRow(at: selectedRowNotNill, animated: true)
    }
}
Danail
источник
1
Это тот, который я ожидаю, что большинство людей захотят, если они не используют UITableViewController. +1
MikeB
3
Интересно, что люди делают сейчас, когда iOS 7 позволяет пользователю «тянуть» назад. Частичное перетаскивание, но не завершение действия вызовет viewWillAppear. Когда пользователь вернется по-настоящему, строка не будет выбрана.
Бен Паккард
1
@BenPackard просто позвони viewDidAppearвместо этого.
квадратная лягушка
@Jessica indexPathForSelectedRowВызов может вернуть ноль, поэтому его следует проверить. В документации говорится : Путь индекса, идентифицирующий индексы строки и раздела выбранной строки, или nil, если путь индекса недопустим.
Гордоний
это следует отметить как принятый ответ, он более дружественный к пользовательскому интерфейсу, поэтому пользователь может вернуться к выбору после возвращения, идеально back
Яхья Альшаар
20

Вы подкласс -(void)viewWillAppear:(BOOL)animated? Выбранный UITableViewCell не будет отменен, если вы не вызываете [super viewWillAppear:animated];свой пользовательский метод.

HansPinckaers
источник
19

Для пользователей Swift добавьте это в свой код:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

Это ответ Paulthenerd, за исключением Swift вместо Obj-C.

Рутгер Хейсманс
источник
1
разве это не отменяется само по себе, я имею в виду момент, когда вы отпускаете?
Мед,
@Honey Возможно, так в предыдущей версии iOS, или после исчезновения представления, но, конечно, не сейчас в iOS 10 (вероятно, даже раньше) и выше.
Джейми Берч
9

Swift 3 Solution

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Оскар
источник
7

Если вы используете UITableViewCell, прокомментируйте следующую строку

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{

 // [super setSelected:selected animated:animated];

}

Надеюсь это поможет.

Шантану
источник
4

Обновлено с Swift 4

После нескольких экспериментов, также основанных на предыдущих ответах, я пришел к выводу, что наилучшего поведения можно достичь двумя способами: (практически идентично на практике)

// First Solution: delegate of the table View
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: false)
}

// Second Solution: With the life cycle of the view.
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        tableView.deselectRow(at: selectedRow, animated: false)
    }
}

Я лично принимаю первое решение, потому что оно просто более лаконично. Другая возможность, если вам нужно немного анимации, когда вы вернетесь к своему tableView, это использовать viewWillAppear:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let selectedRow: IndexPath? = _view.tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        _view.tableView.deselectRow(at: selectedRow, animated: true)
    }
}

И последнее, но не менее важное: если вы используете UITableViewController, вы также можете воспользоваться свойством clearsSelectionOnViewWillAppear .

Алессандро Франчуччи
источник
3

Чтобы получить поведение, которое Кендалл Хелмстеттер Гелнер описывает в своем комментарии, вам, скорее всего, не нужен deselectRowAtIndexPath, а скорее свойство clearsSelectionOnViewWillAppear на вашем контроллере. Возможно, это было установлено в ДА случайно?

См. Комментарий в шаблоне Apple по умолчанию для новых подклассов UITableViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
}
Дейв Тир
источник
2

Я получал эту проблему также для моего приложения детализации. После того, как viewcontroller, который я назову VC, возвращается после нажатия другого ViewController, выбранная ячейка в VC остается выделенной. В моем приложении я создал VC для обработки второго уровня (из трех уровней) моего анализа.

Проблема в моем случае состоит в том, что VC был UIViewController (который содержал View, который содержал TableView). Вместо этого я сделал VC UITableViewController (который содержал TableView). Класс UITableViewController автоматически обрабатывает отмену выделения ячейки таблицы после возврата из толчка. Второй ответ на пост « Проблема с deselectRowAtIndexPath в tableView » дает более полный ответ на эту проблему.

Проблема не возникла для корневого viewcontroller, потому что, когда я создал приложение как «Приложение на основе навигации» в XCode, полученный корневой viewcontroller уже был создан для подкласса UITableViewController.

stackoverflowuser2010
источник
1

Если ни один из них не работает для вас, рассмотрите этот обходной путь:

Используйте раскрутить Segue, чтобы позвонить:

@IBAction func unwind_ToTableVC (segue: UIStoryboardSegue) {
    if let index = tableView.indexPathForSelectedRow {
        tableView.deselectRowAtIndexPath(index, animated: true)
    }
}

Зачем это делать? Прежде всего, если у вас возникли проблемы с запуском кода отмены выбора в нужное время. У меня были проблемы с тем, что он не работал с viewWillAppear, поэтому раскрутка работала намного лучше.

шаги:

  1. Запишите результаты раскрутки (или вставьте сверху) в свой первый ВК (тот, что со столом)

  2. Перейти на 2-й ВК. Удерживая нажатой клавишу «Control», нажмите кнопку «Отмена» / «Готово» и т. Д., Которую вы используете, чтобы закрыть VC, и перетащите на значок «Выход» вверху.

  3. Выберите секцию раскрутки, созданную на шаге 1

    Удачи.

Дэйв Дж
источник
Это лучшее решение для случаев, когда viewDidAppear не запускается (т. Е. Если дочерний вид представлен модально в виде листа формы и не покрывает весь экран).
Pheedsta
1

Я использую CoreData, поэтому код, который работал для меня, представлял собой комбинацию идей из различных ответов в Swift:

override func viewDidAppear(_ animated: Bool) {
    if let testSelected = yourTable.indexPathForSelectedRow {
        yourTable.deselectRow(at: testSelected, animated: true)
    }
    super.viewDidAppear(true)
}
Yewzr
источник
1
 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
чернь
источник
0

У меня была такая же проблема в течение долгого времени, поэтому на случай, если кто-то еще борется:

Посмотрите на свой -tableView: cellForRowAtIndexPath:и посмотрите, создаете ли вы ячейки или используете «идентификатор повторного использования». Если последнее, убедитесь, что в вашей таблице в IB есть ячейка с этим идентификатором. Если вы не используете идентификатор повторного использования, просто создайте новую ячейку для каждой строки.

Это должно дать вашей таблице ожидаемое «исчезновение выбранной строки» при появлении.

LearningAsIGo
источник
0

Используйте этот метод в классе UITableViewCell

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

   // Just comment This line of code
   // [super setSelected:selected animated:animated];        
}
солнечно
источник
0

Для Swift 3: я бы предпочел использовать его в viewDidDisappear

Определить: -

    var selectedIndexPath = IndexPath()

По мнениюDidDisappear: -

    override func viewDidDisappear(_ animated: Bool) {
    yourTableView.deselectRow(at: selectedIndexPath, animated: true)
}

В didSelectRowAtIndexPath: -

    func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
    selectedIndexPath = indexPath
}
Иршад Куреши
источник
0

если ячейка остается выделенной после прикосновения к ней, вы можете вызвать метод UITabelView,

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

`[tableView deselectRowAtIndexPath:indexPath animated:YES];`   

}

Или вы можете использовать следующий метод и изменить его в соответствии с вашими требованиями,

// MARK: UITableViewDelegate

func tableView(tableView: UITableView, didHighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.greenColor()
  }
}

func tableView(tableView: UITableView, didUnhighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.blackColor()
  }
} 
Варша Шивхаре
источник
0

Xcode 10, Swift 4

У меня была такая же проблема, и я обнаружил, что оставил пустой вызов viewWillAppear в нижней части моего tableViewController. После того, как я удалил пустую функцию переопределения, строка больше не оставалась подсвеченной после возврата к представлению tableView.

проблемный функционал

override func viewWillAppear(_ animated: Bool) {
  // need to remove this function if not being used.
}

удаление пустой функции решило мою проблему.

Robac
источник
0

Решение Swift 5:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Зогу
источник