UITableview: Cách vô hiệu hóa lựa chọn cho một số hàng nhưng không phải cho người khác


298

Tôi đang hiển thị trong một tableviewnội dung nhóm được phân tích cú pháp từ XML. Tôi muốn tắt sự kiện nhấp vào nó (Tôi hoàn toàn không thể nhấp vào nó) Bảng chứa hai nhóm. Tôi muốn vô hiệu hóa lựa chọn cho nhóm đầu tiên nhưng không phải nhóm thứ hai. Nhấp vào hàng đầu tiên của nhóm thứ hai navigatesvào ống của tôi player view.

Làm thế nào tôi có thể làm cho chỉ các nhóm hoặc hàng cụ thể có thể lựa chọn?

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

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

Cảm ơn.

Câu trả lời:


499

Bạn chỉ cần đặt mã này vào cellForRowAtIndexPath

Để tắt thuộc tính lựa chọn của ô: (trong khi nhấn vào ô)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Để cho phép có thể chọn (nhấn) ô: (nhấn vào ô)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

Lưu ý rằng một ô selectionStyle = UITableViewCellSelectionStyleNone;vẫn sẽ khiến UI gọi didSelectRowAtIndexPathkhi người dùng chạm vào. Để tránh điều này, hãy làm như đề xuất dưới đây và thiết lập.

cell.userInteractionEnabled = NO;

thay thế. Cũng lưu ý rằng bạn có thể muốn đặt cell.textLabel.enabled = NO;màu xám ra khỏi mục.


1
Phương pháp này sẽ tạo ra lỗi nếu bạn cố gắng vuốt để xóa.
Vive

116
Đây là hack! Làm điều đó, sử dụng câu trả lời dưới đây - sử dụng willSelectRowAtIndexPath với trả về nil!
Peter Stajger

4
Công cụ userInteractionEnables không chính xác, thay vào đó hook hookSelectRowAtIndexPath như mọi người lưu ý.
Jonny

23
Trên iOS 6.0 trở lên, tableView:shouldHighlightRowAtIndexPath:là một UITableViewDelegatephương thức mới trả về BOOLdựa trên việc có nên tô sáng hay không indexPath. Nếu bạn đang xây dựng phiên bản 6.0 trở lên, tôi thực sự khuyên dùng API mới này.
cbowns

3
nếu bạn đang làm điều này trong Swift và bạn đang gặp sự cố nhưng kết thúc tại đây, bạn sẽ cần thiết lập cell!.selectionStyle = .Nonelực lượng nào mở khóa ô, cho phép bạn truy cập các thuộc tính của nó.
Marcos

371

Nếu bạn muốn tạo một hàng (hoặc tập hợp con của các hàng) không thể chọn , hãy triển khai UITableViewDelegatephương thức -tableView:willSelectRowAtIndexPath:(cũng được TechZen đề cập). Nếu indexPathkhông nên chọn , trả lại nil, nếu không thì trả lại indexPath. Để có được hành vi lựa chọn mặc định, bạn chỉ cần trả lại indexPathtruyền cho delegatephương thức của mình , nhưng bạn cũng có thể thay đổi lựa chọn hàng bằng cách trả về một cách khác indexPath.

thí dụ:

- (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
Chi tiết nhỏ: bạn ơi <= 2, không = <2. Cười xấu! :)
Jonas Byström

23
Tôi cũng muốn thêm rằng đây là câu trả lời đúng, nhưng bạn cũng nên đặt lựa chọnStyle thành UITableViewCellSelectionStyleNone trong cellForRowAtIndexPath. Tại sao? bởi vì không có kiểu chọn này, ô không thể được chọn nhưng nó sẽ vẫn hiển thị "như đã chọn" khi chạm xuống (vì vậy nó sẽ thay đổi thành màu đã chọn, nếu có một ô cho các ô khác)
TooManyEduardos

4
điều này sẽ có nhiều upvote hơn câu trả lời được chấp nhận
user1244109

2
Tôi nghĩ lý do chính đây không phải là câu trả lời được chấp nhận là vì câu trả lời được chấp nhận dễ dàng hơn. Mặc dù đó không phải là 'cách tốt nhất' để làm điều đó bởi vì bảng của bạn vẫn sẽ gọi setSelected: trên các ô của bạn, nó vẫn hoạt động một cách trực quan. Câu trả lời này ở đây tốn nhiều công sức hơn nhưng là cách thích hợp để thực hiện (bạn cũng phải kết hợp đề xuất @TooManyEduardos) để tránh mọi hậu quả không lường trước được của bảng gọi setSelected: trên các ô của bạn.
Brian Sachetta

Tôi giống như câu trả lời này, nhưng nếu bạn không muốn lặp lại logic của bạn trong cellForRowAtIndexPath và willSelectRowAtIndexPath, chỉ cần kiểm tra nếu cell.selectionStyle == none trong willSelectRowAtIndexPath để trở lại con số không (xem câu trả lời của tôi dưới đây)
Eric D'Souza

61

Bắt đầu từ iOS 6, bạn có thể sử dụng

-tableView:shouldHighlightRowAtIndexPath:

Nếu bạn quay lại NO, nó sẽ vô hiệu hóa cả phần tô sáng lựa chọn và bảng phân cảnh kích hoạt các phân biệt được kết nối với ô đó.

Phương thức này được gọi khi một liên lạc đi xuống trên một hàng. Quay lại NOthông báo đó sẽ tạm dừng quá trình lựa chọn và không làm cho hàng được chọn hiện tại mất giao diện được chọn trong khi chạm xuống.

Tham chiếu giao thức UITableViewDelegate


3
Đã đồng ý. Đối với iOS 7 trở lên, đây phải là phương pháp ưa thích (thực tế trên iOS 8, các phương thức khác không hiệu quả với tôi.)
racing_carr

Đây phải là câu trả lời hàng đầu.
Cameron E

16

Không có câu trả lời nào ở trên thực sự giải quyết vấn đề một cách chính xác. Lý do là chúng tôi muốn vô hiệu hóa lựa chọn ô nhưng không nhất thiết phải là các cuộc phỏng vấn bên trong ô.

Trong trường hợp của tôi, tôi đã trình bày một UISwitch ở giữa hàng và tôi muốn tắt lựa chọn cho phần còn lại của hàng (trống) nhưng không phải cho công tắc! Do đó, cách làm đúng là trong phương pháp

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

trong đó một tuyên bố của mẫu

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

vô hiệu hóa lựa chọn cho ô cụ thể đồng thời cho phép người dùng thao tác chuyển đổi và do đó sử dụng bộ chọn thích hợp. Điều này không đúng nếu ai đó vô hiệu hóa tương tác của người dùng thông qua

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

phương pháp chỉ đơn thuần là chuẩn bị tế bào và không cho phép tương tác với UISwitch.

Hơn nữa, sử dụng phương pháp

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

để bỏ chọn ô với một tuyên bố có dạng

[tableView deselectRowAtIndexPath:indexPath animated:NO];

vẫn hiển thị hàng đang được chọn trong khi người dùng nhấn vào nội dung ban đầu của ô.

Chỉ hai xu của tôi. Tôi khá chắc chắn nhiều người sẽ tìm thấy điều này hữu ích.


Đồng ý. Và trả về nil in willSelectRowAtIndexPathcó cùng một vấn đề, các cuộc phỏng vấn không thể lựa chọn.
jeffjv

Cũng lưu ý rằng nếu bạn có một bảng tĩnh, bạn chỉ có thể đặt Lựa chọn thành Không có trong Trình tạo giao diện cho các ô mà bạn không muốn lựa chọn xuất hiện.
jeffjv

11

Bạn bẫy các lựa chọn với các phương pháp nguồn dữ liệu này.

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

Trong các phương thức này, bạn kiểm tra xem hàng đã chọn có phải là hàng bạn muốn chọn không. Nếu có, hãy hành động, nếu không, không làm gì cả.

Thật không may, bạn không thể tắt lựa chọn cho chỉ một phần. Đó là toàn bộ bàn hoặc không có gì.

Tuy nhiên, bạn có thể đặt thuộc tính ô bảng selectionStylethành UITableViewCellSelectionStyleNone. Tôi tin rằng sẽ làm cho sự lựa chọn vô hình. Kết hợp với các phương pháp trên sẽ làm cho các ô trông hoàn toàn trơ từ quan điểm của người dùng.

Chỉnh sửa01:

Nếu bạn có một bảng trong đó chỉ có một số hàng có thể chọn, điều quan trọng là các ô của các hàng có thể chọn phải khác biệt trực quan với các hàng không thể chọn. Nút phụ kiện chevron là cách mặc định để làm điều này.

Tuy nhiên, bạn làm điều đó, bạn không muốn người dùng của mình cố gắng chọn các hàng và nghĩ rằng ứng dụng đã bị hỏng vì hàng không làm gì cả.


vui lòng giải thích cách sử dụng các phương pháp này hoặc cung cấp một số liên kết chương trình mẫu
Chiến binh

2
@War Warrior: Nếu bạn đã cài đặt SDK, bạn có thể mở Xcode, truy cập Help -> Developer documentation, sau đó sao chép các tên phương thức đó vào trường tìm kiếm để xem cách nó hoạt động. Tài liệu dành cho nhà phát triển cũng chứa mã mẫu.
kennytm


9

Bạn cần làm một cái gì đó như sau để vô hiệu hóa lựa chọn ô trong cellForRowAtIndexPathphương thức:

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

Để hiển thị ô màu xám, đặt các mục sau trong tableView:WillDisplayCell:forRowAtIndexPathphương thức:

[cell setAlpha:0.5];

Một phương pháp cho phép bạn kiểm soát sự tương tác, phương pháp khác cho phép bạn kiểm soát giao diện người dùng.


5

Để chỉ dừng một số ô đang được chọn, hãy sử dụng:

cell.userInteractionEnabled = NO;

Cùng với việc ngăn lựa chọn, điều này cũng dừng bảngView: didSelectRowAtIndexPath: được gọi cho các ô đã đặt.


1
Một điều kỳ lạ xảy ra mọi lúc: khi tôi đặt userInteractionEnabledthành KHÔNG trên một ô (rõ ràng hơn, một indexPath), tương tác người dùng của một số ô KHÁC bị vô hiệu hóa. Tôi không biết tại sao điều này xảy ra mỗi khi tôi sử dụng userInteractionEnabledtrên các ô xem bảng. Đây có phải là một lỗi đã biết hay tôi đã làm gì đó sai?
Philip007

3
@ Philip007 Các tế bào "KHÔNG" có được sử dụng lại không? Nếu vậy, bạn có thể cần đảm bảo rằng bạn đặt nó thành "CÓ" khi bạn hủy bỏ một ô.
JosephH

1
Tại sao lại đặt thành "CÓ"? Tôi muốn nó là NO (tương tác người dùng disallow) .. Một ví dụ điển hình là tôi thiết lập tương tác người dùng của dòng đầu tiên ( if [indexPath row] == 0) để NOtableView:cellForRowAtIndexPath:sau khi dequeueing tế bào. Nó thường hoạt động tốt lúc đầu. Rồi sau vài cuộc gọi reloadData, đột nhiên hàng thứ năm không được phép tương tác, rồi hàng thứ tư .. Tôi không thể biết khi nào nó sẽ xảy ra. Toàn bộ điều này có vẻ ngẫu nhiên.
Philip007

6
@ Philip007 Nếu bạn đang sử dụng lại các tế bào, bạn sẽ cần phải thiết lập lại nó để "YES" cho các tế bào bạn DO muốn được tương tác. Mặt khác, nếu một ô "KHÔNG" được sử dụng lại trong một hàng mà bạn muốn tương tác, nó sẽ vẫn bị vô hiệu hóa. tức là:if [indexPath row] == 0) { set to NO } else { set to YES }
JosephH

5

Bạn có thể sử dụng tableView:willDisplayCellphương thức để thực hiện tất cả các loại tùy chỉnh cho bảngViewCell.

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

Trong đoạn mã trên, người dùng chỉ có thể chọn hàng đầu tiên trong phần thứ hai của bảngView. Phần còn lại tất cả các hàng không thể được chọn. Cảm ơn! ~


5

Đối với nhanh chóng:

cell.selectionStyle = .None
cell.userInteractionEnabled = false

5

Giải pháp của tôi dựa trên mô hình dữ liệu:

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

Đối với swift 4.0 Điều này sẽ thực hiện các mẹo. Nó sẽ vô hiệu hóa Cell trong phương thức didSelectRowAtIndexPath nhưng giữ cho các lần xem có thể nhấp được.

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

Hay nói ngắn gọn là: return indexPath.row == clickableIndex ? indexPath : nilgiữ cho mã của bạn sạch hơn một chút ;-)
Đánh dấu

1

Sử dụng điều này để làm cho ô trông giống như nó bị vô hiệu hóa và không thể chọn:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Quan trọng: lưu ý rằng đây chỉ là một thuộc tính kiểu dáng và không thực sự vô hiệu hóa ô. Để làm điều đó, bạn phải kiểm tra việc triển khai đại biểu selectionStylecủa mình 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

Tôi thích câu trả lời của Brian Chapados ở trên. Tuy nhiên, điều này có nghĩa là bạn có thể đã nhân đôi logic trong cả cellForRowAtIndexPath và sau đó trong willSelectRowAtIndexPath có thể dễ dàng thoát khỏi đồng bộ hóa. Thay vì sao chép logic, chỉ cần kiểm tra selectStyle:

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

    else
        return indexPath;
}

1

Tôi thấy điều này tiện dụng vì nó hoạt động với cả bảng tĩnh và động. Tôi chỉ đặt chỉ báo tiết lộ trên các ô mà tôi muốn cho phép lựa chọn.

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

1

trên Xcode 7 mà không cần mã hóa, bạn chỉ cần làm như sau:

Trong chế độ xem phác thảo, chọn Ô xem bảng. (Ô được lồng trong Cảnh điều khiển xem bảng> Trình điều khiển xem bảng> Chế độ xem bảng. Bạn có thể phải tiết lộ các đối tượng đó để xem ô xem bảng)

Trong Trình kiểm tra thuộc tính, tìm trường có nhãn Lựa chọn và chọn Không có. thanh tra thuộc tính Với tùy chọn này, ô sẽ không có được một điểm nổi bật trực quan khi người dùng chạm vào nó.


0

ĐƠN GIẢN

Chỉ cần sử dụng cell.userInteractionEnabled = YES;đến ô nếu nó có thể điều hướng và cell.userInteractionEnabled = NO;nếu không


1
Điều này cũng ngăn tương tác với bất kỳ chế độ xem phụ kiện nào trong ô, có thể không phải là hành vi mong muốn.
Greg Brown

0

Thực hiện chỉ phương thức tableView:willSelectRowAtIndexPath: trong nguồn dữ liệu cho bảng của bạn. Nếu bạn muốn hàng ở đường dẫn được tô sáng, hãy trả về indexPath đã cho. Nếu bạn không, trở về con số không.

Ví dụ từ ứng dụng của tôi:

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

Điều tuyệt vời ở đây là shouldPerformSegueWithIdentifier:sender:sẽ không được gọi nếu phương thức trên trả về con số không, mặc dù tôi lặp lại thử nghiệm ở trên chỉ để hoàn thiện.



0

Tôi đồng ý với câu trả lời của Bryan

nếu tôi làm

cell.isUserInteractionEnabled = false 

sau đó các cuộc phỏng vấn trong ô sẽ không được người dùng tương tác.

Trên trang khác, cài đặt

cell.selectionStyle = .none

sẽ kích hoạt phương thức didSelect mặc dù không cập nhật màu lựa chọn.

Sử dụng willSelectRowAt là cách tôi giải quyết vấn đề của mình. Thí dụ:

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 từ tableView.allowsMultipleSelection = truebạn sẽ cần bỏ chọn phần còn lại của các ô của phần khi chọn:

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

đối với swift 3.0, bạn có thể sử dụng mã bên dưới để vô hiệu hóa tương tác của người dùng với ô UITableView

 cell.isUserInteractionEnabled = false
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.