UITableview: Как отключить выделение для некоторых строк, но не для других


298

Я отображаю в группе tableviewсодержимое, проанализированное из XML. Я хочу отключить событие щелчка по нему (я вообще не смогу его щелкнуть). Таблица содержит две группы. Я хочу отключить выбор только для первой группы, но не для второй группы. Нажав на первый ряд второй группы navigatesна мою трубку player view.

Как я могу сделать только определенные группы или строки по выбору?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if(indexPath.section!=0)
    if(indexPath.row==0)    

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:tubeUrl]];   
}

Спасибо.

Ответы:


499

Вы просто должны поместить этот код в cellForRowAtIndexPath

Чтобы отключить свойство выбора ячейки: (при касании ячейки)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Чтобы включить возможность выбрать (нажать) ячейку: (касание ячейки)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

Обратите внимание, что ячейка с selectionStyle = UITableViewCellSelectionStyleNone;вызовом пользовательского интерфейса будет вызываться didSelectRowAtIndexPathпри прикосновении пользователя. Чтобы избежать этого, сделайте как предложено ниже и установите.

cell.userInteractionEnabled = NO;

вместо. Также обратите внимание, что вы можете установить cell.textLabel.enabled = NO;серый цвет элемента.


1
Этот метод создаст ошибку, если вы попытаетесь провести пальцем, чтобы удалить.
Vive

116
Это взломать! Сделайте это, используйте ответ ниже - используя willSelectRowAtIndexPath с возвратом nil!
Питер Стайгер

4
Материал userInteractionEnabled не верный, вместо этого перехватите willSelectRowAtIndexPath, как отмечают люди.
Джонни

23
В iOS 6.0 и более поздних версиях tableView:shouldHighlightRowAtIndexPath:это новый UITableViewDelegateметод, который возвращает в BOOLзависимости от того, indexPathдолжен ли выделенный элемент выделяться. Если вы используете 6.0 и более поздние версии, я настоятельно рекомендую этот новый API.
cbowns

3
если вы делаете это в Swift и у вас возникли проблемы, но в итоге вы оказались здесь, вам нужно установить, cell!.selectionStyle = .Noneкакая сила разворачивает ячейку, позволяя вам получить доступ к ее свойствам.
Маркос

371

Если вы хотите сделать строку (или подмножество строк) невыбираемой , реализуйте UITableViewDelegateметод -tableView:willSelectRowAtIndexPath:(также упомянутый TechZen). Если indexPathне следует выбирать , верните nil, в противном случае верните indexPath. Чтобы получить поведение выбора по умолчанию, вы просто возвращаете indexPathпереданный в ваш delegateметод метод, но вы также можете изменить выбор строки, вернув другой indexPath.

пример:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // rows in section 0 should not be selectable
    if ( indexPath.section == 0 ) return nil;

    // first 3 rows in any section should not be selectable
    if ( indexPath.row <= 2 ) return nil;

    // By default, allow row to be selected
    return indexPath;
}

2
Маленькая деталь: вы мент <= 2, а не = <2. Плохой смайлик! :)
Йонас Быстрем

23
Я также хотел бы добавить, что это правильный ответ, но вы также должны установить для selectionStyle значение UITableViewCellSelectionStyleNone в cellForRowAtIndexPath. Зачем? потому что без этого стиля выбора ячейка не может быть выбрана, но она все равно будет отображаться «как выбрано» при касании (поэтому она меняет цвет на выбранный, если есть один для других ячеек)
TooManyEduardos

4
это должно иметь больше голосов, чем принятый ответ
user1244109

2
Я думаю, что главная причина того, что это не принятый ответ, состоит в том, что принятый ответ легче. Хотя это не самый лучший способ сделать это, потому что ваша таблица будет по-прежнему вызывать setSelected: в ваших ячейках она все еще работает визуально. Этот ответ здесь требует больше работы, но является правильным способом сделать это (вы должны также объединить предложение @TooManyEduardos), чтобы избежать любых непредвиденных последствий вызова таблицы setSelected: для ваших ячеек.
Брайан Сашетта

Мне нравится этот ответ, но если вы не хотите дублировать свою логику в cellForRowAtIndexPath и willSelectRowAtIndexPath, просто проверьте, не содержит ли cell.selectionStyle == none в willSelectRowAtIndexPath значение nil (см. Мой ответ ниже)
Эрик Д'Суза,

61

Начиная с iOS 6, вы можете использовать

-tableView:shouldHighlightRowAtIndexPath:

Если вы вернетесь NO, он отключит подсветку выделения и сегменты, запускаемые раскадровкой, связанные с этой ячейкой.

Метод вызывается, когда касание падает на строку. Возврат NOк этому сообщению останавливает процесс выбора и не приводит к тому, что выбранная строка в данный момент теряет выбранный вид, пока касание не работает.

Ссылка на протокол UITableViewDelegate


3
Согласовано. Для iOS 7 и выше это должен быть предпочтительный метод (фактически на iOS 8 другие методы не работали для меня.)
race_carr

Это должен быть главный ответ.
Кэмерон Э

16

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

В моем случае я представлял UIS-переключатель в середине строки и хотел отключить выбор для остальной части строки (которая пуста), но не для переключателя! Правильный способ сделать это, следовательно, в методе

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

где утверждение формы

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

отключает выбор для конкретной ячейки, в то же время позволяет пользователю манипулировать переключателем и, следовательно, использовать соответствующий селектор. Это не так, если кто-то отключает взаимодействие с пользователем через

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

метод, который просто подготавливает ячейку и не позволяет взаимодействовать с UISwitch.

Кроме того, используя метод

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

чтобы отменить выбор ячейки с заявлением в форме

[tableView deselectRowAtIndexPath:indexPath animated:NO];

по-прежнему показывает выбранную строку, пока пользователь нажимает на исходный contentView ячейки.

Просто мои два цента. Я уверен, что многие найдут это полезным.


Согласен. И возвращение nil в willSelectRowAtIndexPathимеет ту же проблему, подпредставления не выбираются.
jeffjv

Также обратите внимание, что если у вас есть статическая таблица, вы можете просто установить «Выделение» на «Нет» в Интерфейсном Разработчике для ячеек, для которых выбор не должен отображаться.
Jeffjv

11

Вы перехватываете выборки с помощью этих методов источника данных.

 tableView:willSelectRowAtIndexPath: 
 tableView:didSelectRowAtIndexPath: 
 tableView:willDeselectRowAtIndexPath: 
 tableView:didDeselectRowAtIndexPath:

В этих методах вы проверяете, является ли выбранная строка той, которую вы хотите выбрать. Если это так, принять меры, если нет, ничего не делать.

К сожалению, вы не можете отключить выбор только для одного раздела. Это весь стол или ничего.

Однако вы можете установить для selectionStyleсвойства ячейки таблицы значение UITableViewCellSelectionStyleNone. Я считаю, что сделает выбор невидимым. В сочетании с описанными выше методами, которые должны заставить клетки выглядеть полностью инертными с точки зрения пользователя.

Edit01:

Если у вас есть таблица, в которой выбираются только некоторые строки, важно, чтобы ячейки выбираемых строк визуально отличались от невыбираемых строк. Кнопка аксессуара шеврона - способ сделать это по умолчанию.

Однако вы не хотите, чтобы ваши пользователи пытались выбрать строки и думали, что приложение работает неправильно, потому что строка ничего не делает.


пожалуйста, опишите, как использовать эти методы, или дайте примеры ссылок на программы
Warrior

2
@Warrior: Если вы установили SDK, вы можете открыть XCode, перейти Help -> Developer documentation, затем скопировать имена этих методов в поле поиска, чтобы увидеть, как он работает. Документация разработчика также содержит пример кода.
Kennytm


9

Вам нужно сделать что-то вроде следующего, чтобы отключить выбор ячейки в cellForRowAtIndexPathметоде:

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell setUserInteractionEnabled:NO];

Чтобы ячейка отображалась серым цветом, поместите в tableView:WillDisplayCell:forRowAtIndexPathметод следующее:

[cell setAlpha:0.5];

Один метод позволяет вам контролировать интерактивность, другой позволяет контролировать внешний вид пользовательского интерфейса.


5

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

cell.userInteractionEnabled = NO;

Наряду с предотвращением выделения это также останавливает tableView: didSelectRowAtIndexPath: вызывается для ячеек, для которых он установлен.


1
Странная вещь случается все время: когда я устанавливаю userInteractionEnabledNO на одну ячейку (точнее, один indexPath), пользовательское взаимодействие некоторых ДРУГИХ ячеек отключается. Я понятия не имею, почему это происходит каждый раз, когда я использую userInteractionEnabledячейки табличного представления. Это известная ошибка или я что-то не так сделал?
Philip007

3
@ Philip007 Повторно ли используются ячейки "НЕТ"? Если это так, вам может потребоваться установить значение «ДА» при снятии очереди с ячейки.
JosephH

1
Зачем устанавливать «ДА»? Я хочу, чтобы оно было НЕТ (запретить взаимодействие с пользователем). Типичным примером является то, что я устанавливаю пользовательское взаимодействие в первой строке ( if [indexPath row] == 0) в NOin tableView:cellForRowAtIndexPath:после удаления очереди из ячейки. Сначала все работает нормально. Затем, после нескольких вызовов reloadData, вдруг пятый ряд запрещает взаимодействие, затем четвертый ряд ... Я не могу понять, когда это произойдет. Все выглядит случайным.
Philip007

6
@ Philip007 Если вы повторно клетки, вам нужно будет сбросить его в «YES» для ячеек DO хотите быть интерактивным. В противном случае, если ячейка «НЕТ» будет повторно использована в строке, которую вы хотите использовать интерактивно, она все равно будет отключена. то есть:if [indexPath row] == 0) { set to NO } else { set to YES }
Иосиф

5

Вы можете использовать tableView:willDisplayCellметод, чтобы выполнить все виды настройки для tableViewCell.

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
     [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
     [cell setUserInteractionEnabled:NO];

     if (indexPath.section == 1 && indexPath.row == 0)
     {
         [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
         [cell setUserInteractionEnabled:YES];
     }
} 

В этом коде выше пользователь может выбрать только первую строку во втором разделе tableView. Остальные все строки не могут быть выбраны. Спасибо! ~



5

Мое решение на основе модели данных:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled ? indexPath : nil
}

func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled
}

5

Для Swift 4.0 это сделает свое дело. Он отключит ячейку в методе didSelectRowAtIndexPath, но при этом подпредставления будут активными.

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
         if (indexPath.row == clickableIndex ) { 
            return indexPath
         }else{
            return nil
        }
    }

Или для краткости: return indexPath.row == clickableIndex ? indexPath : nilсохраняет ваш код немного чище ;-)
Марк

1

Используйте это, чтобы ячейка выглядела как отключенная и недоступная для выбора:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Важное замечание: обратите внимание, что это только свойство стиля, которое фактически не отключает ячейку. Чтобы сделать это, вы должны проверить selectionStyleв вашей didSelectRowAtIndexPath:реализации делегата:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if(cell.selectionStyle == UITableViewCellSelectionStyleNone) {
        return;
    }

    // do your cell selection handling here
}

1

Мне нравится ответ Брайана Чападоса выше. Однако это означает, что у вас может быть дублированная логика как в cellForRowAtIndexPath, так и в willSelectRowAtIndexPath, которая может легко выйти из синхронизации. Вместо дублирования логики, просто проверьте selectionStyle:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.selectionStyle == UITableViewCellSelectionStyleNone)
        return nil;

    else
        return indexPath;
}

1

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

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.accessoryType != UITableViewCellAccessoryDisclosureIndicator) {
        return nil;
    }
    return indexPath;
}

1

на Xcode 7 без кодирования вы можете просто сделать следующее:

В виде структуры выберите Ячейка табличного представления. (Ячейка вложена в «Сцена контроллера табличного представления»> «Контроллер табличного представления»> «Представление таблицы». Возможно, вам придется раскрыть эти объекты, чтобы увидеть ячейку табличного представления)

В инспекторе атрибутов найдите поле с меткой «Выбор» и выберите «Нет». Инспектор атрибутов С помощью этой опции ячейка не будет получать визуальное выделение, когда пользователь нажимает на нее.


0

ПРОСТО

Просто используйте cell.userInteractionEnabled = YES;для клетки, если она может перемещаться и в cell.userInteractionEnabled = NO;противном случае


1
Это также предотвращает взаимодействие с любым дополнительным представлением внутри ячейки, что может не соответствовать желаемому поведению.
Грег Браун

0

Реализуйте только метод tableView:willSelectRowAtIndexPath: в источнике данных для вашей таблицы. Если вы хотите, чтобы строка в пути была выделена, верните указанный indexPath. Если нет, верните ноль.

Пример из моего приложения:

- (NSIndexPath *)tableView:(UITableView *)tableView
    willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MySelectableObj* obj = [self objectAtPath:indexPath];
    if(obj==nil) return nil;
    return indexPath;
}

Хорошая вещь об этом - то, shouldPerformSegueWithIdentifier:sender:что не будет вызван, если вышеупомянутый метод возвращает ноль, хотя я повторяю тест выше только для полноты.



0

Я согласен с ответом Брайана

если я сделаю

cell.isUserInteractionEnabled = false 

тогда подпредставления внутри ячейки не будут взаимодействовать с пользователем.

На другом сайте настройка

cell.selectionStyle = .none

вызовет метод didSelect, несмотря на то, что цвет обновления не обновляется.

Используя willSelectRow, я решил свою проблему. Пример:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {

    if indexPath.section == 0{

        if indexPath.row == 0{
            return nil
        }

    }
    else if indexPath.section == 1{

        if indexPath.row == 0{
            return nil
        }

    }

    return indexPath

}

0

appart от tableView.allowsMultipleSelection = trueвас нужно будет отменить выбор остальных ячеек раздела при выборе:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.section does not support multiple selection {
        // deselect the rest of cells
        tableView
            .indexPathsForSelectedRows?.compactMap { $0 }
            .filter { $0.section == indexPath.section && $0.row != indexPath.row }
            .forEach { tableView.deselectRow(at: $0, animated: true) }
    }
}

-1

для swift 3.0 вы можете использовать приведенный ниже код, чтобы отключить взаимодействие пользователя с ячейкой UITableView

 cell.isUserInteractionEnabled = false
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.