Чому UITableViewCell залишається виділеним?


145

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

Відповіді:


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

11
Я вважаю за краще викликати deselectRowAtIndexPathв моєму оглядіDidAppear, якщо виберіть рядок відкриває новий вид.
notnoop

5
Насправді це не правильне місце для його виклику, насправді ... спробуйте скористатися додатком Apple із таблицями ("Контакти хороші"), і ви побачите, коли ви перейдете на новий екран, повернення клітина все ще буде виділена незадовго до відміни. Теоретично я вважаю, що вам не доведеться робити зайвих робіт, щоб її негайно скасувати відмітку, тому код у viewDidAppear не потрібен ...
Кендалл Гельмстетер Гельнер

6
@Kendall, @ 4thSpace: Можливо, мій останній коментар був заплутаним щодо того, кого я мав на увазі, вибачте за це. UITableViewController викликає -deselectRowAtIndexPath:animated:метод у своїй властивості tableView з -viewDidAppear. Однак якщо у вас є перегляд таблиці в підкласі UIViewController, вам слід зателефонувати -deselectRowAtIndexPath:animated:від -viewDidAppearсебе. :)
Даніель Тулл

5
У моєму підкласі UITableViewController це насправді переосмислення, -viewWillAppear:яке порушило його. Додано дзвінок, щоб [super viewWillAppear:animated]він знову працював.
Ben Challenor

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

Швидка версія

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)
    }
}

1
Це те, на що я думаю, що більшість людей захоче, якщо вони не використовують UITableViewController. +1
MikeB

3
Цікаво, що зараз роблять люди, коли iOS 7 дозволяє користувачеві «перетягуватися» назад. Часткове перетягування, але потім не завершення дії, призведе до запуску viewWillAppear. Коли користувач повернеться до реального, рядок не буде обраний.
Бен Пакард

1
@BenPackard просто зателефонуйте viewDidAppearзамість цього.
квадратний жаба

@Jessica indexPathForSelectedRowВиклик може повернути нуль, тому його слід перевірити. У документації зазначено : шлях до індексу, що ідентифікує індекси рядків та розділів вибраного рядка, або нульовий, якщо шлях до індексу недійсний.
Гордоніум

це слід зауважити як прийняту відповідь, він більш зручний у користуванні інтерфейсом, щоб користувач міг дійти до вибору після повернення, ідеально 👌
Yahya Alshaar

20

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


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 Рішення

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

Щоб отримати поведінку, яку описує у своєму коментарі Кендалл Хелмстеттер Гельнер, ви, ймовірно, не хочете, щоб ви вибрали деселектРоуAtIndexPath, а, скоріше, властивість clersSelectionOnViewWillAppear на контролері. Можливо, це було задано ТАК випадково?

Дивіться коментар у стандартному шаблоні Apple для нових підкласів UITableViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
}

2

Цю проблему я отримував і для свого додаткового додатку. Після того, як контролер перегляду, який я називаю VC, повертається після натискання іншого ViewController, вибрана комірка в VC залишається виділеною. У своєму додатку я створив VC для обробки другого рівня (з трьох рівнів) моєї деталізованої роботи.

Проблема в моєму випадку полягає в тому, що VC був UIViewController (який містив представлення, що містило TableView). Я замість цього зробив VC UITableViewController (який містив TableView). Клас UITableViewController автоматично обробляє розмежування комірки таблиці після повернення з натискання. Друга відповідь на пост " Проблема з deselectRowAtIndexPath у tableView " дає більш повну відповідь на цю проблему.

Проблема не виникала для кореневого контролера перегляду, тому що коли я створив додаток як "додаток для навігації" в XCode, отриманий кореневий вигляд-контролер вже був зроблений для підкласу UITableViewController.


1

Якщо жодне з цих питань не працює для вас, врахуйте це:

Використовуйте розмотаний мозок, щоб зателефонувати:

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

Навіщо це робити? Перш за все, якщо у вас виникають проблеми з тим, щоб скинути код відбору в потрібний час. У мене були проблеми з тим, що я не працював на viewWillAppear, тому розмотка працювала набагато краще.

Кроки:

  1. Запишіть розмотаний мозок (або вставте зверху) у свій 1-й ВК (той із таблицею)

  2. Перейти до 2-го ВК. Перетягніть клавішу "Control" / "Скасувати" / "Готово" та "Etc", яку ви використовуєте, щоб відхилити цей VC, та перетягніть його до значка "Вихід" вгорі.

  3. Виберіть розмотаний мозок, який ви створили на кроці 1

    Удачі.


Це найкраще рішення для періодів, коли viewDidAppear не спрацьовує (тобто, якщо подання дитини представлено модально як аркуш форми та не охоплює весь екран).
Федеста

1

Я використовую CoreData, тому код, який працював на мене, був поєднанням ідей з різних відповідей у ​​Swift:

override func viewDidAppear(_ animated: Bool) {
    if let testSelected = yourTable.indexPathForSelectedRow {
        yourTable.deselectRow(at: testSelected, animated: true)
    }
    super.viewDidAppear(true)
}

1
 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}

0

У мене з цим питанням вже давно, тому у випадку, якщо хтось інший бореться:

Погляньте на своє -tableView: cellForRowAtIndexPath:і перевірте, чи створюєте ви комірки або використовуєте ідентифікатор повторного використання. Якщо остання, переконайтеся, що у вашій таблиці в IB є комірка з цим ідентифікатором. Якщо ви не використовуєте ідентифікатор повторного використання, просто створіть нову комірку для кожного рядка.

Тоді це повинно дати вашій таблиці очікуване "зникнення вибраного рядка" після появи.


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 внизу моєї таблиціViewController. Після того, як я видалив порожню функцію заміщення, після повернення до подання tableView рядок більше не виділявся.

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

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

видалення порожньої функції вирішило мою проблему.


0

Рішення Swift 5:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.