2010-06-14 18 views
38

Jak dodać UITableView do mojej aplikacji opartej na widoku, w której użytkownik dotknie więcej niż jednej komórki, i zostanie wybrany tak, jak ustawienie "Nowy alarm" aplikacji Zegar o nazwie "Powtórz" (Zegar> Alarmy> +> Powtórz) i jak mogę uzyskać wszystkie wybrane komórki w tablicy?UITableView Wybór wielokrotny

+0

Psh. Nie widziałem na tym przykładu Apple'a. –

Odpowiedz

27

W swojej implementacji -tableView:didSelectRowAtIndexPath: ustawisz właściwość komórki widoku tabeli w zależności od jej bieżącej wartości (aby była włączana i wyłączana za pomocą wielu naciśnięć). Na przykład:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path { 
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:path]; 

    if (cell.accessoryType == UITableViewCellAccessoryCheckmark) { 
     cell.accessoryType = UITableViewCellAccessoryNone; 
    } else { 
     cell.accessoryType = UITableViewCellAccessoryCheckmark; 
    } 
} 

Można też utrzymać tablicę wybranych stanach oprócz własnego państwa akcesoria typu komórki lub iteracyjne nad komórkami w zapytań widok tabeli dla każdego z nich w stanie, aby odczytać wybrane wiersze.

+15

To nie zadziała - indexPath odnosi się do niewłaściwej komórki, gdy zaznaczona jest komórka i przewiniesz. W rezultacie zobaczysz wiele elementów zaznaczonych. –

+0

Tak jak w poprzednim komentarzu, to nie będzie działać tak, jak wiele pozycji wybranych podczas przewijania. – Siddharth

+2

-1 To rozwiązanie ma problem, po wybraniu niektórych wierszy i przewinięciu można zobaczyć wiele znaczników wyboru dla komórek, które jeszcze nie zostały wybrane. – raaz

1

Widok tabeli powtarzania alarmów zegara nie jest wielokrotnym wyborem. Pomyśl o tym jako o zapalonym polach wyboru.

Po wybraniu komórki kolor czcionki i typ akcesoriów zostają zmienione, a wybór zanika. Po zaznaczeniu zaznaczonej komórki kolor czcionki i typ akcesorium zostają zmienione, a wybór zanika.

W swojej metodzie delegatów didSelectRowAtIndexPath należy ustawić kolor tekstu i typ akcesorium dla wybranej komórki, a następnie odznaczyć komórkę. Zapisałbyś również nowy stan w swoim modelu danych. Może to być tak proste, jak bitowa maska ​​reprezentująca wybrany stan, ale zależy od wyświetlanych danych.

W metodzie cellForRowAtIndexPath: dataSource ustaw kolor tekstu i typ akcesoriów na podstawie modelu danych.

Rzeczywisty wybór wielokrotny byłby podobny. Musisz śledzić, które komórki są wybrane i ustawić wybraną komórkę każdego stanu, tak jak jest tworzony lub pokazywany. Gdy widok tabeli zgłasza, że ​​komórka jest zaznaczona, przełącz stan zaznaczenia w swoim modelu danych i odpowiednio ustaw wybrany stan komórki.

14

Tylko krótka wskazówka oprócz świetnej odpowiedzi powyżej: naśladowanie stylu Apple'a z aplikacji zegara (wybór koloru wygaszania rzędu po odznaczeniu/odznaczeniu wiersza), dodaj to do didSelectRowAtIndexPath, po warunkowych :

[self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 

Z przewodnika firmy Apple: TableMultiSelect.

14
self.tableView.allowsMultipleSelection = YES; 
102

Dla wielokrotnego wyboru, należy dodać linię poniżej w viewDidLoad()

tableView.allowsMultipleSelection = true 

skonfigurować każdy cell po zdejmującą z kolejki (lub inicjowanie) go w tableView(_:cellForRowAt:)

let selectedIndexPaths = tableView.indexPathsForSelectedRows 
let rowIsSelected = selectedIndexPaths != nil && selectedIndexPaths!.contains(indexPath) 
cell.accessoryType = rowIsSelected ? .checkmark : .none 
// cell.accessoryView.hidden = !rowIsSelected // if using a custom image 

Aktualizacja każda komórka, gdy jest wybrany/odznaczone

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
    let cell = tableView.cellForRow(at: indexPath)! 
    cell.accessoryType = .checkmark 
    // cell.accessoryView.hidden = false // if using a custom image 
} 

override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { 
    let cell = tableView.cellForRow(at: indexPath)! 
    cell.accessoryType = .none 
    // cell.accessoryView.hidden = true // if using a custom image 
} 

Kiedy skończysz, dostać tablicę wszystkich wybranych wierszy

let selectedRows = tableView.indexPathsForSelectedRows 

i uzyskać wybrane dane, gdzie dataArray mapy do rzędów widok z tabeli z tylko 1 części

let selectedData = selectedRows?.map { dataArray[$0.row].ID } 
+7

Nie rozumiem, dlaczego nie jest to zaakceptowana odpowiedź ... jeśli używasz komórki niestandardowej, możesz również zmienić wygląd w komórce użytkownika setSelected: animated: metoda oparta na stanie komórki – keisar

+0

Świetnie! Działa jak marzenie. Najlepsza odpowiedź na to pytanie. Doceniam to! – sermilion

+3

Aby uzyskać wybrane obiekty indeksy NSArray * selectedCells = [self.tableView indexPathsForSelectedRows]; – iCoder86

18

@BrendanBreg implementation nie pracował dla mnie. @RaphaelOliveira dostarczył good solution, ale kiedy przewiniesz swój stół w dół - wybrane zostaną nieprawidłowe wiersze (ponieważ UITableView buforuje to komórki). Tak, mam nieco zmodyfikowane rozwiązanie Rafaela:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath]; 
    cell.accessoryType = UITableViewCellAccessoryCheckmark; 
} 

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath]; 
    cell.accessoryType = UITableViewCellAccessoryNone; 
} 

/*Here is modified part*/ 

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    /* 
    ... 
    Your implementation stays here 
    we're just adding few lines to make sure 
    that only correct rows will be selected 
    */ 

    if([[tableView indexPathsForSelectedRows] containsObject:indexPath]) { 
     cell.accessoryType = UITableViewCellAccessoryCheckmark; 
    } else { 
     cell.accessoryType = UITableViewCellAccessoryNone; 
    } 
} 
+0

Podczas przewijania ukrywa wybrane wiersze! – Saqib

1

Nie możesz OFF indexPath ponieważ komórki, które odnosi się do zmian, jak scoll. Umieść NSLog w cellForRowAtIndexPath, aby to zobaczyć. Możesz to zaznaczyć/odznaczyć w willSelectRowAtIndexPath lub didSelectRowAtIndexPath. Obejmuje to tylko początkowe sprawdzenie lub odznaczenie, a także sprawi, że rzeczy zostaną wyświetlone jako zaznaczone po przewinięciu, ponieważ zmienia się podstawowa komórka dla danej zmiennej IndexPath.

Rozwiązaniem, które znalazłem, jest posiadanie tablicy wybranych rzeczy z czymś, co jest specyficzne dla danej komórki i wykonanie początkowego sprawdzenia.

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath]; 

    if (![selectedIndexes containsObject:cell.textLabel.text]){ 
    [selectedIndexes addObject:cell.textLabel.text]; 
    cell.accessoryType = UITableViewCellAccessoryCheckmark; 
    } else { 
    [selectedIndexes removeObject:cell.textLabel.text]; 
    cell.accessoryType = UITableViewCellAccessoryNone; 
    } 

    return indexPath; 
} 

Trzeba też mieć logikę w cellForRowAtIndexPath aby upewnić się, że prawo rzeczy jest sprawdzane, czy nie, jak widok zwoje:

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

    ... 

    cell.accessoryType = UITableViewCellAccessoryNone; 
    if ([selectedIndexes containsObject:cell.textLabel.text]) { 
    cell.accessoryType = UITableViewCellAccessoryCheckmark; 
    [cell setSelected:YES animated:YES]; 
    } 

    return cell; 
} 
+0

-1 IndexPath w tableView: didDeselectRowAtIndexPath: NIE zależy od przewijania i nie ma potrzeby utrzymywania osobnej tablicy wybranych elementów. Zobacz rozwiązanie @Dmitry dla prawidłowej implementacji – fishinear

3

Widziałem ten problem z tak wielu deweloperów. Ze względu na charakter ponownego użycia komórki widoku tabeli usuwa lub przypadkowo sprawdza. Stworzyłem dla tego działające rozwiązanie. Sklonuj/pobierz kod z projektu DevelopmentSupportWorkspace i wykonaj tam projekt UITableViewTest.

Oto kod letni na to:

@interface CheckBoxTestTableViewController() 

@property (nonatomic, strong) NSArray *dataArray; 
@property (nonatomic, strong) NSMutableDictionary *selectedIndexDictionary; 

@end 

@implementation CheckBoxTestTableViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

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

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 
    // self.navigationItem.rightBarButtonItem = self.editButtonItem; 

    // 
    _dataArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ImageList" ofType:@"plist"]]; 
    _selectedIndexDictionary = [NSMutableDictionary dictionary]; 
} 

- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

#pragma mark - Table view data source 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return _dataArray.count; 
} 


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"checkMarkCell" forIndexPath:indexPath]; 
    cell.accessoryType = UITableViewCellAccessoryNone; 

    // Configure the cell... 
    cell.textLabel.text = _dataArray[indexPath.row][@"text"]; 
    if (_selectedIndexDictionary[indexPath] != nil) cell.accessoryType = UITableViewCellAccessoryCheckmark; 

    return cell; 
} 

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath { 
    if (_selectedIndexDictionary[indexPath] == nil) { 
     [_selectedIndexDictionary setObject:_dataArray[indexPath.row] forKey:indexPath]; 
     [[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark]; 
    }else{ 
     [_selectedIndexDictionary removeObjectForKey:indexPath]; 
     [[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryNone]; 
    } 
// [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
} 
@end 
1

1 - Pozwól wielokrotnego wyboru i przełączniki wybranego państwa:

tableView.allowsMultipleSelection = true 

2 - Zebrać lub uzyskać tablicę wszystkich wybranych indeksów gdy jesteś wykonane:

let selected = tableView.indexPathsForSelectedRows 

Uwaga: Jest to niezależne od tego, które komórki są obecnie wyświetlane na ekranie.

3 - Zmień wygląd komórki w zależności od wybranego stanu: Zastąp tę metodę w podklasie UITableViewCell. Jeśli nie masz podklasy, zrób ją.

// In UITableViewCell subclass 
override func setSelected(selected: Bool, animated: Bool) { 
    super.setSelected(selected, animated: animated) 
    accessoryType = selected ? .Checkmark : .None 
}