✔ Zaznacz wybrany wiersz w UITableViewCell

93

Jestem nowicjuszem w rozwoju iOS. Chcę dodać znacznik wyboru do mojego, UITableViewCellgdy jest zaznaczony. Zaznaczenie powinno zostać usunięte po wybraniu innego wiersza. Jak bym to zrobił?

Suchi
źródło

Odpowiedzi:

206

Nie używaj [tableview reloadData]; // to młotek.

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

-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
Ujwal Manjunath
źródło
6
Co się stanie, jeśli chcę tylko znacznika wyboru i chcę odznaczyć wiersz po zaznaczeniu?
gyozo kudor
wybiera ten sam wiersz indeksu w każdej sekcji @Ujwal Manjunath
bLacK hoLE
1
- (void) reloadData powinno być stosunkowo tanie, zgodnie z dokumentacją. Niemniej jednak jest to bardziej przyjemne semantycznie.
MattD,
Dlaczego nie powinieneś używać „[tableview reloadData]”? Chcę użyć wyboru wielokrotnego w moim widoku tabeli. Używam obiektów otrzymanych z serwera, aby ustawić znacznik wyboru w mojej komórce tableview. Kiedyś to robię, zapisuję obiekty check w tablicy globalnej. Jednak gdy używam tej tablicy do porównania wewnątrz mojej metody „didSelectRowAtIndexPath”, aby sprawdzić, czy ścieżka indexpath pasuje do tego obiektu w mojej tablicy globalnej. Nie jestem w stanie tego znaleźć. Myślę, że jego [tableView reloadData]. Co o tym myślisz Proszę o poradę.
Ron
1
Powyższe odpowiedzi nie działają, jeśli ponownie wykorzystałeś komórkę do przechowywania dużej liczby danych. Na przewijaniu możesz zobaczyć powtarzający się znacznik wyboru. Sprawdź moje rozwiązanie stackoverflow.com/questions/7982944/…
Dishant
81

W metodzie UITableViewDatasource:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if(cell == nil )
    {
        cell =[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }
    if ([indexPath compare:self.lastIndexPath] == NSOrderedSame) 
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } 
    else 
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    return cell;
}

// UITableView Delegate Method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    self.lastIndexPath = indexPath;

    [tableView reloadData];
}

LastIndexPath to plik property(strong) NSIndexPath* lastIndexPath;

0x8badf00d
źródło
22

Zauważyłem, że ponowne załadowanie danych w brzydki sposób przerywa animację odznaczania.

Ta implementacja Swift czysto dodaje / usuwa znaczniki wyboru i usuwa zaznaczenie wiersza:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if self.lastSelection != nil {
        self.myTableView.cellForRowAtIndexPath(self.lastSelection)?.accessoryType = .None
    }

    self.myTableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark

    self.lastSelection = indexPath

    self.myTableView.deselectRowAtIndexPath(indexPath, animated: true)
}

gdzie lastSelectionjest zadeklarowany jakovar lastSelection: NSIndexPath!

Żadna dodatkowa aktywność nie jest cellForRowAtIndexPathpotrzebna. Nie powinno być trudne do odtworzenia w Obj-C.

Harry Nelken
źródło
12

Aby ustawić znacznik wyboru:

UITableViewCell *cell = ...;
cell.accessoryType = UITableViewCellAccessoryCheckmark;

Aby zaznaczyć / odznaczyć komórkę:

[cell setSelected:TRUE animated:TRUE]; // select
[cell setSelected:FALSE animated:TRUE]; // deselect

Aby odznaczyć poprzednią komórkę, użyj NSIndexPath * lastSelected ivar do śledzenia ostatnio wybranej komórki:

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
   if (self.lastSelected==indexPath) return; // nothing to do

   // deselect old
   UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
   old.accessoryType = UITableViewCellAccessoryNone;
   [old setSelected:FALSE animated:TRUE];

   // select new
   UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
   cell.accessoryType = UITableViewCellAccessoryCheckmark;
   [cell setSelected:TRUE animated:TRUE];

   // keep track of the last selected cell
   self.lastSelected = indexPath;
}
Jano
źródło
8

Zaktualizuj Swift 4

  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .none
    }
Puji Wahono
źródło
7
extension ViewController : UITableViewDelegate,UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.dataArray.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = dataArray[indexPath.row]
        if selectedData.contains(dataArray[indexPath.row]) {
            cell.accessoryType = .checkmark
        }else{
            cell.accessoryType = .none
        }
        return cell
    }


    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        if selectedData.contains(dataArray[indexPath.row]) {
            selectedData.removeLast()
            tableView.cellForRow(at: indexPath)?.accessoryType = .none
        }else {
            selectedData.removeAll()
            selectedData.append(dataArray[indexPath.row])
            tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
        }
        print(selectedData)
    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .none
    }

}

na podstawie utworzonego widoku tabeli dataArray ... podobnie wziąłem pustą tablicę i za każdym razem, gdy użytkownik dotknie komórki, na podstawie indexValue z dataArray zapisałem ten obiekt w selectedDataArray

Jeśli chodzi o pytanie, to jest jak ... Pytanie ma wiele opcji (odpowiedzi), ale ostatecznie tylko jedna lub żadna odpowiedź będzie wynikiem

wprowadź opis obrazu tutaj

Podobnie, tylko jedna komórka powinna wyświetlać znacznik wyboru, a pozostałe komórki powinny pozostać niezaznaczone ... w niektórych przypadkach możesz odznaczyć swoją odpowiedź ... Mam nadzieję, że to najlepsza odpowiedź na to pytanie

wprowadź opis obrazu tutaj

Singam madhukar
źródło
Ta pierwsza linia nadal nie jest sformatowana jako kod. Użyj interpunkcji!
buhtz
6

Myślę, że łatwiej jest ustawić akcesorium w niestandardowej implementacji UITableViewCell. Szybko użyłem:

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
    accessoryType = selected ? .checkmark : .none
}
Don Miguel
źródło
1
Ta odpowiedź jest niedoceniana przez przestępców.
WaaleedKhan
Dzięki @WaaleedKhan
Don Miguel
4

Używanie Swift 4.2 i Swift 5 Działający kod znacznika wyboru tylko dla wybranego wiersza w TableView

   func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    self.tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    //print(self.coloursArray[indexPath.row])

     self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
M Murteza
źródło
3

Zakładając, że należysz do klasy, która dziedziczy UITableViewController, to załatwia sprawę w Swift 3:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // Add a visual cue to indicate that the cell was selected.
    self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    // Invoked so we can prepare for a change in selection.
    // Remove previous selection, if any.
    if let selectedIndex = self.tableView.indexPathForSelectedRow {
        // Note: Programmatically deslecting does NOT invoke tableView(:didSelectRowAt:), so no risk of infinite loop.
        self.tableView.deselectRow(at: selectedIndex, animated: false)
        // Remove the visual selection indication.
        self.tableView.cellForRow(at: selectedIndex)?.accessoryType = .none
    }
    return indexPath
}
Janus Varmarken
źródło
2

mała literówka

// deselect old
UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
cell.accessoryType = UITableViewCellAccessoryNone;
[cell setSelected:FALSE animated:TRUE];

powinien przeczytać

// deselect old
UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
old.accessoryType = UITableViewCellAccessoryNone;
[old setSelected:FALSE animated:TRUE];

a także w

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == [previouslySelected intValue])
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        selectedIndex = indexPath;
        [cell setSelected:YES animated:YES];
    }
    else
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [cell setSelected:NO animated:YES];
    }
} 

gdzie poprzednioWybrany jest twój lokalny ivar itp. w ten sposób, jeśli przeładujesz wybrany indeks, zostanie on również odznaczony, gdy będziesz przewijać możliwe wybory.

Morph
źródło
2

Powyższe odpowiedzi nie działają, jeśli ponownie wykorzystałeś komórkę do przechowywania dużej liczby danych. Na przewijaniu możesz zobaczyć powtarzający się znacznik wyboru. Aby uniknąć wykonania poniższych kroków:

  1. zadeklaruj zmienną: var indexNumber: NSInteger = -1

  2. Dodaj poniższy kod w cellforRowAtIndexPath:

     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{         
           if indexNumber == indexPath.row{
               cell.accessoryType = .checkmark
           }else{
               cell.accessoryType = .none
           }
    }
    
  3. A w didselectAtIndexpath dodaj poniższy kod:

override func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .checkmark    
indexNumber = indexPath.row
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
       tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .none
}
Dishant
źródło
2

Lepiej spojrzeć na ten problem z innej strony. Przełóż całą pracę na wewnętrzne mechanizmy UIKit i przenieś implementację do UITableViewCell:

@implementation MYTableViewCell

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    self.accessoryType = selected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
}

- (void)prepareForReuse {
    [super prepareForReuse];
    self.accessoryType = UITableViewCellAccessoryNone;
}

@end
Al Zonke
źródło
1

Po prostu didSelectRowAtIndexPathwywołaj metodę, gdy wybierzesz dowolny wiersz, aby wyświetlić CheckMark i wybierz wiersz znacznika wyboru, aby ukryć CheckMark.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:true];
    NSLog(@"touch");

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.accessoryType == UITableViewCellAccessoryNone)
    {
       cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
    else
    {
       cell.accessoryType = UITableViewCellAccessoryNone;
    }
}
Priyank Jotangiya
źródło
1

swift 4 w razie potrzeby.

var lastSelection: NSIndexPath!
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {


    //CHECK MARK THE CELL
    if self.lastSelection != nil {
        self.tableView.cellForRow(at: self.lastSelection as IndexPath)?.accessoryType = .none
    }

    self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark

    self.lastSelection = indexPath as NSIndexPath

    self.tableView.deselectRow(at: indexPath, animated: true)

}
programistów
źródło
1

Możesz to zrobić na dwa sposoby. jeden jest bez wielu wyborów, a drugi z wieloma wyborami.

// Table View Controller -- without Multiple Selection

// Step 1

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    if(tableView.cellForRow(at: indexPath)?.imageView?.image == UIImage(systemName:"checkmark.circle")) {
         tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"circle")
    } else {
         tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"checkmark.circle")
    }
}

//Step 2

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    cell.textLabel?.text = employeeValues[indexPath.row]
    cell.imageView?.image = UIImage(systemName:"circle")

    return cell
}

//  Table View Controller -- with Multiple Selection

@IBOutlet var myTableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()
    self.myTableView.allowsMultipleSelection = true
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    cell.textLabel?.text = employeeValues[indexPath.row]
    cell.imageView?.image = UIImage(systemName:"circle")

    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

//   let cell = tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.checkmark

    tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"checkmark.circle")

}

override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

    tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"circle")  
}
Mirza Q Ali
źródło
0

Powyższy kod działa tylko z pojedynczym wyborem . Poniższy kod z pewnością będzie działał dla wielu wyborów .

- (void)viewDidLoad {
    arrSelectionStatus =[NSMutableArray array]; //arrSelectionStatus holds the cell selection status 
    for (int i=0; i<arrElements.count; i++) { //arrElements holds those elements which will be populated in tableview
        [arrSelectionStatus addObject:[NSNumber numberWithBool:NO]];
    }
}

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    if (cell==nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    }

    cell.textLabel.text=[arrElements objectAtIndex:indexPath.row];

    if ([[arrSelectionStatus objectAtIndex:indexPath.row] boolValue] == YES)
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    else
        cell.accessoryType = UITableViewCellAccessoryNone;

    return cell;
}

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

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType = UITableViewCellAccessoryCheckmark;

    [arrSelectionStatus replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:YES]];
}

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

    [arrSelectionStatus replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:NO]];
}
Polacy
źródło
0

Po ponownym zaznaczeniu wybranej komórki (ze znacznikiem wyboru) po prostu usuń zaznaczenie.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
    BOOL isSelected = ([tableView cellForRowAtIndexPath:indexPath].accessoryType ==  UITableViewCellAccessoryCheckmark);
    if(isSelected){
        [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
        [tableView deselectRowAtIndexPath:indexPath animated:YES]; //this won't trigger the didDeselectRowAtIndexPath, but it's always a good idea to remove the selection
    }else{
        [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
    }
}

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

Premia:

Służy self.tableView.indexPathForSelectedRowdo wykrywania ścieżki indexPath dla wybranej komórki

Kesong Xie
źródło
0
// Check or Uncheck a cell 
        if let cell = tableView.cellForRow(at: indexPath) {
            if cell.accessoryType == .checkmark {
                cell.accessoryType = .none
            } else {
                cell.accessoryType = .checkmark
            }
        }

Teja Goud
źródło