✔ Đánh dấu chọn hàng đã chọn trong UITableViewCell


93

Tôi là một người mới phát triển iOS. Tôi muốn thêm dấu kiểm vào của mình UITableViewCellkhi nó được chọn. Dấu kiểm sẽ được xóa khi một hàng khác được chọn. Tôi sẽ làm điều này như thế nào?

Câu trả lời:


205

Không sử dụng [tableview reloadData]; // nó là một cái búa.

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

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

6
Điều gì sẽ xảy ra nếu tôi chỉ muốn có dấu kiểm và muốn bỏ chọn hàng sau khi lựa chọn?
gyozo kudor

nó chọn cùng một hàng chỉ mục trong mọi phần @Ujwal Manjunath
bLacK hoLE

1
- (void) reloadData nên tương đối rẻ, theo tài liệu. Tuy nhiên, điều này dễ chịu hơn về mặt ngữ nghĩa.
MattD

Tại sao bạn không nên sử dụng '[tableview reloadData]'? Tôi muốn sử dụng nhiều lựa chọn trong chế độ xem bảng của mình. Tôi đang sử dụng các đối tượng nhận được từ máy chủ để đặt dấu kiểm trong ô chế độ xem bảng của mình. Một lần, tôi làm điều đó, tôi lưu các đối tượng kiểm tra trong một mảng toàn cục. Tuy nhiên, khi tôi sử dụng mảng đó để so sánh bên trong phương thức 'didSelectRowAtIndexPath' của mình để xem liệu đường dẫn chỉ mục có khớp với đối tượng này bên trong mảng toàn cầu của tôi hay không. Tôi không thể tìm thấy nó. Tôi nghĩ đó là [tableView reloadData]. Bạn nghĩ gì? Xin lời khuyên.
Ron

1
Các câu trả lời trên không hoạt động nếu bạn sử dụng lại ô cho số lượng lớn dữ liệu. Khi cuộn, bạn có thể thấy dấu kiểm lặp lại. Kiểm tra giải pháp của tôi stackoverflow.com/questions/7982944/…
Không hài lòng

81

Trong phương thức UITableViewDatasource của bạn:

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

Và lastIndexPath là một property(strong) NSIndexPath* lastIndexPath;


22

Tôi thấy rằng việc tải lại dữ liệu sẽ làm gián đoạn hoạt ảnh bỏ chọn theo một cách xấu xí.

Việc triển khai Swift này thêm / xóa các dấu kiểm và bỏ chọn hàng một cách rõ ràng:

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

nơi lastSelectionđược tuyên bố làvar lastSelection: NSIndexPath!

Không cần hoạt động thêm cellForRowAtIndexPath. Sẽ không khó để sao chép trong Obj-C.


12

Để đặt dấu kiểm:

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

Để chọn / bỏ chọn một ô:

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

Để bỏ chọn ô trước đó, hãy sử dụng ivar NSIndexPath * lastSelected để theo dõi ô được chọn cuối cùng:

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

7

Cập nhật 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
    }

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

}

dựa trên dạng xem bảng dataArray được hình thành .. tương tự, tôi lấy một mảng trống và bất cứ khi nào người dùng nhấn vào một ô, dựa trên indexValue của dataArray, tôi đã lưu trữ đối tượng đó trong selectDataArray

Đối với câu hỏi giống như ... Một câu hỏi có nhiều lựa chọn (Câu trả lời), Nhưng cuối cùng chỉ có một hoặc không có câu trả lời nào sẽ là kết quả

nhập mô tả hình ảnh ở đây

Tương tự như vậy, chỉ một ô nên hiển thị dấu kiểm và các ô còn lại không được chọn ... trong một số trường hợp, bạn có thể bỏ chọn câu trả lời của mình ... Tôi hy vọng đây là câu trả lời tốt nhất cho câu hỏi này

nhập mô tả hình ảnh ở đây


Dòng đầu tiên này vẫn chưa được định dạng dưới dạng mã. Sử dụng dấu chấm câu!
buhtz

4

Sử dụng Swift 4.2 và swift 5 Mã làm việc của dấu kiểm cho chỉ hàng đã chọn trong 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
}

3

Giả sử bạn đang ở trong một lớp kế thừa UITableViewController, đây là mẹo trong 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
}

3

Tôi nghĩ việc đặt phụ kiện trong quá trình triển khai UITableViewCell tùy chỉnh của bạn sẽ tốt hơn. Trong thời gian nhanh chóng, tôi đã sử dụng:

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

    // Configure the view for the selected state
    accessoryType = selected ? .checkmark : .none
}

1
Câu trả lời này được đánh giá thấp về mặt hình sự.
WaaleedKhan

Cảm ơn @WaaleedKhan
Don Miguel

2

lỗi đánh máy nhỏ

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

nên đọc

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

và cũng trong

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

nơi đã chọn trước đây là ivar cục bộ của bạn, v.v. theo cách đó nếu bạn tải lại với một chỉ mục đã chọn, nó cũng sẽ được bỏ chọn khi bạn lướt qua các lựa chọn có thể.


2

Các câu trả lời trên không hoạt động nếu bạn sử dụng lại ô cho số lượng lớn dữ liệu. Khi cuộn, bạn có thể thấy dấu kiểm lặp lại. Để tránh sử dụng các bước dưới đây:

  1. khai báo trên biến: var indexNumber: NSInteger = -1

  2. Thêm mã bên dưới vào cellforRowAtIndexPath:

     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{         
           if indexNumber == indexPath.row{
               cell.accessoryType = .checkmark
           }else{
               cell.accessoryType = .none
           }
    }
  3. Và trong didselectAtIndexpath thêm mã bên dưới:

ghi đè 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
}

2

Tốt hơn là nên đối mặt với vấn đề này từ hướng khác. Đặt tất cả công việc trên các cơ chế UIKit nội bộ và chuyển triển khai sang 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

1

Chỉ gọi didSelectRowAtIndexPathPhương thức khi chọn bất kỳ hàng nào để Hiển thị CheckMark và Chọn hàng dấu kiểm để ẩn 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;
    }
}

1

nhanh chóng 4 trong trường hợp bạn cần.

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)

}

1

Có hai cách bạn có thể làm. một là không có nhiều lựa chọn và một là có nhiều lựa chọn.

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

0

Đoạn mã được đề cập ở trên chỉ hoạt động với một lựa chọn . Đoạn mã sau đây chắc chắn sẽ hoạt động cho nhiều lựa chọn .

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

0

Khi một ô được chọn (với dấu kiểm được chọn lại), chỉ cần xóa vùng chọn.

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

Tặng kem:

Sử dụng self.tableView.indexPathForSelectedRowđể phát hiện indexPath cho ô đã chọn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.