UITableview: Jak wyłączyć zaznaczanie dla niektórych wierszy, ale nie dla innych


298

Wyświetlam w grupie tableviewzawartość przeanalizowaną z XML. Chcę wyłączyć na nim zdarzenie kliknięcia (nie powinienem być w stanie go kliknąć) Tabela zawiera dwie grupy. Chcę wyłączyć zaznaczanie tylko dla pierwszej grupy, ale nie dla drugiej grupy. Kliknięcie pierwszego rzędu drugiej grupy navigatesdo mojej rurki player view.

Jak mogę wybrać tylko określone grupy lub wiersze?

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

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

Dzięki.

Odpowiedzi:


499

Musisz tylko wstawić ten kod cellForRowAtIndexPath

Aby wyłączyć właściwość wyboru komórki: (podczas stukania komórki)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Aby umożliwić wybranie (dotknięcie) komórki: (stuknięcie komórki)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

Zauważ, że komórka z selectionStyle = UITableViewCellSelectionStyleNone;nadal spowoduje, że interfejs użytkownika zadzwoni didSelectRowAtIndexPathpo dotknięciu przez użytkownika. Aby tego uniknąć, wykonaj czynności opisane poniżej i ustaw.

cell.userInteractionEnabled = NO;

zamiast. Pamiętaj też, że możesz chcieć cell.textLabel.enabled = NO;wyszarzyć element.


1
Ta metoda wygeneruje błąd, jeśli spróbujesz przeciągnąć, aby usunąć.
Vive

116
To jest hack! Zrób to, użyj odpowiedzi poniżej - używając willSelectRowAtIndexPath ze zwracającym zero!
Peter Stajger

4
Element userInteractionEnabled jest niepoprawny, zamiast tego przechwytuje willSelectRowAtIndexPath, jak zauważają ludzie.
Jonny

23
W systemie iOS 6.0 i nowszych tableView:shouldHighlightRowAtIndexPath:jest nowa UITableViewDelegatemetoda, która zwraca wartość BOOLzależną od tego, czy zaliczone indexPathpowinno być wyróżnione. Jeśli tworzysz wersję 6.0 lub nowszą, zdecydowanie polecam ten nowy interfejs API.
cbowns

3
jeśli robisz to w Swift i masz problemy, ale skończyło się tutaj, musisz ustawić, cell!.selectionStyle = .Nonektóra siła rozpakowuje komórkę, umożliwiając dostęp do jej właściwości.
Marcos,

371

Jeśli chcesz, aby wiersz (lub podzbiór wierszy) nie był wybierany , zaimplementuj UITableViewDelegatemetodę -tableView:willSelectRowAtIndexPath:(wspomnianą również przez TechZen). Jeśli indexPathnie można wybrać , zwróć nil, w przeciwnym razie zwróć indexPath. Aby uzyskać domyślne zachowanie zaznaczania, po prostu przywróć indexPathprzekazaną delegatemetodę, ale możesz także zmienić zaznaczenie wiersza, zwracając inną indexPath.

przykład:

- (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
Mały szczegół: masz na myśli <= 2, a nie = <2. Zła buźka! :)
Jonas Byström

23
Chciałbym również dodać, że jest to poprawna odpowiedź, ale powinieneś również ustawić opcję selectionStyle na UITableViewCellSelectionStyleNone w cellForRowAtIndexPath. Dlaczego? ponieważ bez tego stylu selekcji komórka nie może zostać wybrana, ale po dotknięciu w dół nadal będzie wyświetlać „jak wybrano” (więc zmienia się na wybrany kolor, jeśli jest taki dla innych komórek)
TooManyEduardos

4
powinno to mieć więcej głosów pozytywnych niż zaakceptowana odpowiedź
użytkownik1244109

2
Myślę, że głównym powodem, dla którego nie jest to akceptowana odpowiedź, jest to, że zaakceptowana odpowiedź jest łatwiejsza. Chociaż nie jest to „najlepszy sposób”, aby to zrobić, ponieważ twoja tabela nadal wywoła setSelected: w twoich komórkach nadal działa wizualnie. Ta odpowiedź tutaj wymaga więcej pracy, ale jest właściwym sposobem, aby to zrobić (musisz również połączyć sugestię @TooManyEduardos), aby uniknąć nieprzewidzianych konsekwencji wywołania tabeli setSelected: na twoich komórkach.
Brian Sachetta

Podoba mi się ta odpowiedź, ale jeśli nie chcesz powielać logiki w cellForRowAtIndexPath i willSelectRowAtIndexPath, po prostu sprawdź, czy cell.selectionStyle == none w willSelectRowAtIndexPath zwraca zero (patrz moja odpowiedź poniżej)
Eric D'Souza

61

Począwszy od iOS 6, możesz używać

-tableView:shouldHighlightRowAtIndexPath:

Jeśli wrócisz NO, spowoduje to wyłączenie zarówno podświetlania wyboru, jak i sekwensów w serii ujęć powiązanych z tą komórką.

Metoda jest wywoływana, gdy dotknięcie zejdzie w rzędzie. Powrót NOdo tej wiadomości zatrzymuje proces selekcji i nie powoduje, że aktualnie wybrany wiersz traci wybrany wygląd, gdy dotyk jest wciśnięty.

Dokumentacja protokołu UITableViewDelegate


3
Zgoda. W przypadku systemu iOS 7 i
nowszego

To powinna być najlepsza odpowiedź.
Cameron E

16

Żadna z powyższych odpowiedzi tak naprawdę nie rozwiązuje problemu poprawnie. Powodem jest to, że chcemy wyłączyć zaznaczenie komórki, ale niekoniecznie widoki podrzędne wewnątrz komórki.

W moim przypadku prezentowałem UISwitch na środku wiersza i chciałem wyłączyć zaznaczanie dla reszty wiersza (który jest pusty), ale nie dla przełącznika! Właściwy sposób na zrobienie tego jest stąd w metodzie

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

gdzie oświadczenie formularza

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

wyłącza selekcję dla określonej komórki, jednocześnie umożliwiając użytkownikowi manipulowanie przełącznikiem, a tym samym użycie odpowiedniego selektora. Nie jest to prawdą, jeśli ktoś zablokuje interakcję użytkownika za pośrednictwem

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

metoda, która jedynie przygotowuje komórkę i nie pozwala na interakcję z UISwitch.

Ponadto przy użyciu metody

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

w celu usunięcia zaznaczenia komórki za pomocą instrukcji formularza

[tableView deselectRowAtIndexPath:indexPath animated:NO];

nadal pokazuje wybrany wiersz, podczas gdy użytkownik naciska na oryginalną zawartość Wyświetl widok komórki.

Tylko moje dwa centy. Jestem pewien, że wielu uzna to za przydatne.


Zgodzić się. A zwracanie wartości zero willSelectRowAtIndexPathma ten sam problem, nie można wybierać widoków podrzędnych.
jeffjv

Zauważ również, że jeśli masz statyczną tabelę, możesz po prostu ustawić Zaznaczenie na Brak w Konstruktorze interfejsów dla komórek, których zaznaczenie nie ma się pojawiać.
jeffjv

11

Wyłapujesz selekcje za pomocą tych metod źródła danych.

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

W tych metodach sprawdzasz, czy wybrany wiersz to taki, który chcesz wybrać. Jeśli tak, podejmij działania, jeśli nie, nie rób nic.

Niestety nie można wyłączyć wyboru tylko dla jednej sekcji. To cały stół albo nic.

Możesz jednak ustawić selectionStylewłaściwość komórek tabeli na UITableViewCellSelectionStyleNone. Wierzę, że dzięki temu wybór będzie niewidoczny. W połączeniu z powyższymi metodami, które powinny sprawić, że komórki będą wyglądać całkowicie obojętnie z perspektywy użytkownika.

Edycja01:

Jeśli masz tabelę, w której można wybierać tylko niektóre wiersze, ważne jest, aby komórki wybranych wierszy były wizualnie różne od wierszy, których nie można wybrać. Przycisk akcesoriów Chevron jest domyślnym sposobem na zrobienie tego.

Jakkolwiek to zrobisz, nie chcesz, aby użytkownicy próbowali wybierać wiersze i sądzili, że aplikacja źle działała, ponieważ wiersz nic nie robi.


wyjaśnij, jak korzystać z tych metod lub podaj linki do przykładowych programów
Warrior

2
@ Warrior: Jeśli masz zainstalowany SDK, możesz otworzyć Xcode, przejdź do Help -> Developer documentation, a następnie skopiuj nazwy metod do pola wyszukiwania, aby zobaczyć, jak to działa. Dokumentacja programisty zawiera również przykładowy kod.
kennytm


9

Musisz zrobić coś takiego jak poniżej, aby wyłączyć selekcję komórek w ramach cellForRowAtIndexPathmetody:

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

Aby pokazać komórkę wyszarzoną, umieść w tableView:WillDisplayCell:forRowAtIndexPathmetodzie:

[cell setAlpha:0.5];

Jedna metoda pozwala kontrolować interaktywność, druga pozwala kontrolować wygląd interfejsu użytkownika.


5

Aby zatrzymać tylko wybrane komórki, użyj:

cell.userInteractionEnabled = NO;

Oprócz zapobiegania selekcji, zatrzymuje to również tableView: didSelectRowAtIndexPath: wywoływane dla komórek, które mają ustawione.


1
Dziwna rzecz zdarza się cały czas: kiedy ustawiam userInteractionEnabledNIE na jedną komórkę (a dokładniej na jedną ścieżkę indeksu), interakcja użytkownika niektórych INNYCH komórek jest wyłączona. Nie mam pojęcia, dlaczego tak się dzieje za każdym razem, gdy korzystam userInteractionEnabledz komórek widoku tabeli. Czy to znany błąd, czy zrobiłem coś złego?
Philip007

3
@ Philip007 Czy komórki „NIE” są ponownie wykorzystywane? Jeśli tak, może być konieczne upewnienie się, że ustawiono opcję „TAK” podczas usuwania z komórki komórki.
JosephH

1
Po co ustawiać „TAK”? Ja ma to, że nie ma (Disallow interakcji użytkownika) .. Typowym przykładem jest to, że zestaw interakcji użytkownika z pierwszego rzędu ( if [indexPath row] == 0), aby NOw tableView:cellForRowAtIndexPath:po dequeueing komórkę. Zwykle na początku działa poprawnie. Potem, po kilku wezwaniach reloadData, nagle piąty rząd jest niedozwolony, a następnie czwarty rząd .. Nie mogę się dowiedzieć, kiedy to nastąpi. Całość wygląda na przypadkową.
Philip007

6
@ Philip007 Jeśli ponowne komórki, trzeba będzie zresetować go na „TAK” dla komórek ty NIE chcą być interaktywne. W przeciwnym razie, jeśli komórka „NIE” zostanie ponownie użyta w rzędzie, który chcesz być interaktywny, nadal będzie wyłączona. tj .:if [indexPath row] == 0) { set to NO } else { set to YES }
JosephH

5

Możesz użyć tej tableView:willDisplayCellmetody, aby wykonać wszelkiego rodzaju dostosowania do 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];
     }
} 

W powyższym kodzie użytkownik może wybrać tylko pierwszy wiersz w drugiej sekcji tableView. Reszty nie można wybrać wszystkich wierszy. Dzięki! ~


5

Dla szybkiego:

cell.selectionStyle = .None
cell.userInteractionEnabled = false

5

Moje rozwiązanie oparte na modelu danych:

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

Dla szybkiego 4.0 To załatwi sprawę. Spowoduje to wyłączenie komórki w metodzie didSelectRowAtIndexPath, ale klikanie widoków podrzędnych będzie możliwe.

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

Lub w skrócie: return indexPath.row == clickableIndex ? indexPath : nilutrzymuje twój kod nieco czystszy ;-)
Mark

1

Użyj tego, aby komórka wyglądała, jakby była wyłączona i nie można jej wybrać:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Ważne: pamiętaj, że jest to tylko właściwość stylizacji i tak naprawdę nie wyłącza komórki. Aby to zrobić, musisz sprawdzić selectionStylew didSelectRowAtIndexPath:implementacji delegata:

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

    // do your cell selection handling here
}

1

Podoba mi się Brian Chapados, odpowiedź powyżej. Oznacza to jednak, że logika może być zduplikowana zarówno w cellForRowAtIndexPath, jak i następnie w willSelectRowAtIndexPath, który łatwo można zsynchronizować. Zamiast powielać logikę, po prostu zaznacz opcję selectionStyle:

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

    else
        return indexPath;
}

1

Znalazłem to przydatne, ponieważ działa zarówno z tabelami statycznymi, jak i dynamicznymi. Ustawiam wskaźnik ujawnienia tylko na te komórki, które chcę umożliwić wybór.

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

1

na Xcode 7 bez kodowania możesz po prostu wykonać następujące czynności:

W widoku konspektu wybierz komórkę widoku tabeli. (Komórka jest zagnieżdżona pod Kontrolą widoku tabeli Scena> Kontroler widoku tabeli> Widok tabeli. Może być konieczne ujawnienie tych obiektów, aby zobaczyć komórkę widoku tabeli)

W Inspektorze atrybutów znajdź pole o nazwie Wybór i wybierz Brak. Atrybut inspektora Dzięki tej opcji komórka nie zostanie podświetlona, ​​gdy użytkownik ją stuknie.


0

PROSTY

Po prostu użyj cell.userInteractionEnabled = YES;do komórki, jeśli może nawigować i cell.userInteractionEnabled = NO;inaczej


1
Zapobiega to również interakcji z dowolnym widokiem akcesoriów w komórce, co może nie być pożądanym zachowaniem.
Greg Brown

0

Zaimplementuj tylko metodę tableView:willSelectRowAtIndexPath: w źródle danych dla swojej tabeli. Jeśli chcesz, aby wiersz przy ścieżce był podświetlony, zwróć podaną ścieżkę indexPath. Jeśli nie, zwróć zero.

Przykład z mojej aplikacji:

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

Zaletą tego jest to, że shouldPerformSegueWithIdentifier:sender:nie zostanie wywołane, jeśli powyższa metoda zwróci zero, chociaż powtarzam powyższy test tylko dla kompletności.



0

Zgadzam się z odpowiedzią Bryana

Jeśli zrobię

cell.isUserInteractionEnabled = false 

wtedy widoki podrzędne w komórce nie będą obsługiwane przez użytkownika.

Z drugiej strony ustawienie

cell.selectionStyle = .none

uruchomi metodę didSelect, mimo że nie zaktualizuje wybranego koloru.

Korzystanie z willSelectRowAt jest sposobem na rozwiązanie mojego problemu. Przykład:

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

odejdź od tej opcji tableView.allowsMultipleSelection = true, aby usunąć zaznaczenie pozostałych komórek w sekcji podczas wybierania:

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

w przypadku wersji 3.0 można użyć poniższego kodu, aby wyłączyć interakcję użytkownika z komórką UITableView

 cell.isUserInteractionEnabled = false
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.