UITableView được đặt thành các ô tĩnh. Có thể ẩn một số tế bào theo chương trình?


Câu trả lời:


48

Bạn đang tìm kiếm giải pháp này:

StaticDataTableViewCont điều khiển 2.0

https://github.com/xelvenone/StaticDataTableViewCont điều khiển

có thể hiển thị / ẩn / tải lại bất kỳ (các) ô tĩnh nào có hoặc không có hình động!

[self cell:self.outletToMyStaticCell1 setHidden:hide]; 
[self cell:self.outletToMyStaticCell2 setHidden:hide]; 
[self reloadDataAnimated:YES];

Lưu ý chỉ luôn sử dụng (reloadDataAnimated: CÓ / KHÔNG) (không gọi trực tiếp [self.tableView reloadData])

Điều này không sử dụng giải pháp hacky với cài đặt chiều cao thành 0 và cho phép bạn tạo hiệu ứng thay đổi và ẩn toàn bộ phần


6
Một vấn đề với giải pháp đó là nó để lại những khoảng trống nơi các tế bào ẩn.
Jack

làm thế nào bạn có nghĩa là khoảng cách? bạn có thể mô tả tốt hơn tình hình, có thể trực tiếp trên github? bạn đã chạy mẫu?
Peter Lapisu

1
Tôi có nghĩa là nếu bạn có ví dụ ba phần và bạn ẩn các ô từ phần giữa thì không gian nơi phần đó vẫn còn. Tôi đã không thử dự án mẫu, nhưng tôi đã thử mã. Tôi sẽ thử mẫu.
Jack

1
kiểm tra mẫu, đã có một bản cập nhật lớn hơn, có thể bạn đã có một số mã cũ ... hoạt động hoàn hảo đối với tôi
Peter Lapisu

Tôi đã thử mẫu và nó dường như hoạt động ở đó, điều duy nhất tôi làm khác là sử dụng IBOutletCollectionnhưng tôi không thấy điều đó sẽ tạo ra sự khác biệt như thế nào. Tôi chỉ tải xuống mã ngày hôm qua vì vậy tôi không nghĩ đó là phiên bản cũ.
Jack

164

Để ẩn các ô tĩnh trong UITable:

  1. Thêm phương thức này :

Trong lớp đại biểu bộ điều khiển UITableView của bạn:

Mục tiêu-C:

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

    if(cell == self.cellYouWantToHide)
        return 0; //set the hidden cell's height to 0

    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

Nhanh:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

Phương thức này sẽ được gọi cho mỗi ô trong UITable. Khi nó gọi nó cho ô bạn muốn ẩn, chúng tôi đặt chiều cao của nó thành 0. Chúng tôi xác định ô mục tiêu bằng cách tạo một lối thoát cho nó:

  1. Trong trình thiết kế, tạo một lối thoát cho (các) ô bạn muốn ẩn. Ổ cắm cho một ô như vậy được gọi là "cellYouWantToHide" ở trên.
  2. Kiểm tra "Clip Subview" trong IB để biết các ô bạn muốn ẩn. Các ô bạn đang ẩn cần phải có ClipToBound = CÓ. Nếu không, văn bản sẽ chồng chất trong UITableView.

10
Giải pháp tốt đẹp. Để tránh sự cố ClipToBounds, bạn cũng có thể đặt ô thành ẩn. Điều này có vẻ sạch hơn đối với tôi. ;-)
Monsieur

13
+1 cho ClipToBound = CÓ. Các giải pháp Numeorus trong các chủ đề khác đã bỏ lỡ điều đó.
Jeff

2
Ý tưởng tuyệt vời. Đây là giải pháp dễ nhất tôi tìm thấy. Các giải pháp khác có mã ở hai hoặc nhiều vị trí. BTW, trong IB, ClipToBound được liệt kê là "Clip Subview".
VaporwareWolf

1
Chỉ cần chỉnh sửa một chút, hãy sử dụng self .cellYouWantToHide thay vì .cellYouWantToHide này .
Zoltan Vinkler

2
mà không tạo đối tượng ô, chúng ta cũng có thể sử dụng "index.row" để ẩn "
uitableviewcell

38

Cách tốt nhất là như được mô tả trong blog sau http://ali-reynolds.com/2013/06/29/ leather-cell-in-static-test-view /

Thiết kế chế độ xem bảng tĩnh của bạn như bình thường trong trình tạo giao diện - hoàn thành với tất cả các ô có khả năng ẩn. Nhưng có một điều bạn phải làm cho mọi ô tiềm năng mà bạn muốn ẩn - kiểm tra phần xem xét Clip Clip thuộc tính của tế bào, nếu không, nội dung của ô sẽ không biến mất khi bạn thử và ẩn nó (bằng cách thu nhỏ chiều cao của nó - Trễ hơn).

SO - bạn có một công tắc trong một ô và công tắc được cho là ẩn và hiển thị một số ô tĩnh. Kết nối nó với IBAction và thực hiện điều này:

[self.tableView beginUpdates];
[self.tableView endUpdates];

Điều đó cung cấp cho bạn hình ảnh động đẹp cho các tế bào xuất hiện và biến mất. Bây giờ thực hiện phương thức đại biểu xem bảng sau:

- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need
    // Show or hide cell
        if (self.mySwitch.on) {
            return 44; // Show the cell - adjust the height as you need
        } else {
            return 0; // Hide the cell
        }
   }
   return 44;
}

Và đó là nó. Lật công tắc và các ô ẩn và xuất hiện lại với một hình ảnh động đẹp, mượt mà.


Cập nhật: bạn cũng cần đặt Nhãn di động thành Ẩn / Hiển thị với bạn Ẩn / Hiển thị, nếu không, Nhãn sẽ tạo ra một mớ hỗn độn.
Mohamed Saleh

1
Bạn nên lưu ý rằng nếu bất kỳ UIView nào trong nội dung của ô tĩnh của bạn có bất kỳ ràng buộc nào đối với cell.content, bạn có thể gặp lỗi thời gian chạy nếu các ràng buộc đó không hợp lệ đối với chiều cao ô mới của bạn.
Pedro Borges

1
Câu trả lời tốt nhất. Cảm ơn.
Eric Chen

1
Tôi biết thủ thuật này làm việc với nội dung động. Hoạt động khá độc đáo với tĩnh quá. Đơn giản quá.
Kiến

2
Điều này thực sự hoạt động, nhưng để che đi một điểm còn thiếu: nếu hàng bị ẩn / hiển thị có chứa bộ chọn ngày, chỉ thực hiện [self.tableView startedUpdates]; [self.tableView endUpdates]; vẫn sẽ để lại một trục trặc trong khi che giấu nó. Để loại bỏ trục trặc, bạn nên gọi [self.tableView reloadRowsAtIndexPaths: @ [indexPathOfTargetRow] vớiRowAnimation: UITableViewRowAnimationNone]; Cũng để ý rằng hoạt hình hàng bằng cách nào đó "bị vô hiệu hóa" ở đây.
Chris

34

Giải pháp của tôi đi theo một hướng tương tự như Gareth, mặc dù tôi làm một số điều khác biệt.

Đây là:

1. Ẩn các ô

Không có cách nào để trực tiếp ẩn các tế bào. UITableViewControllerlà nguồn dữ liệu cung cấp các ô tĩnh và hiện tại không có cách nào để nói với nó "không cung cấp ô x". Vì vậy, chúng tôi phải cung cấp nguồn dữ liệu của riêng mình, đại biểu cho UITableViewControllerđể có được các ô tĩnh.

Dễ nhất là phân lớp UITableViewControllervà ghi đè tất cả các phương thức cần hành xử khác nhau khi ẩn các ô .

Trong trường hợp đơn giản nhất (bảng phần đơn, tất cả các ô có cùng chiều cao), điều này sẽ diễn ra như sau:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section    
{
    return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Recalculate indexPath based on hidden cells
    indexPath = [self offsetIndexPath:indexPath];

    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
{
    int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
    int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
    int offsetRow = indexPath.row + numberOfCellsHiddenAbove;

    return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
}

Nếu bảng của bạn có nhiều phần hoặc các ô có độ cao khác nhau, bạn cần ghi đè thêm các phương thức. Nguyên tắc tương tự được áp dụng ở đây: Bạn cần phải bù indexPath, phần và hàng trước khi ủy quyền cho super.

Ngoài ra, hãy nhớ rằng tham số indexPath cho các phương thức như didSelectRowAtIndexPath:sẽ khác nhau cho cùng một ô, tùy thuộc vào trạng thái (tức là số lượng ô bị ẩn). Vì vậy, có lẽ nên luôn luôn bù bất kỳ tham số indexPath nào và làm việc với các giá trị này.

2. Làm sinh động sự thay đổi

Như Gareth đã nêu, bạn sẽ gặp trục trặc lớn nếu bạn thay đổi hoạt hình bằng cách sử dụng reloadSections:withRowAnimation: phương pháp phương pháp.

Tôi phát hiện ra rằng nếu bạn gọi reloadData: ngay sau đó, hình ảnh động được cải thiện hơn nhiều (chỉ còn những trục trặc nhỏ). Bảng được hiển thị chính xác sau khi hình ảnh động.

Vì vậy, những gì tôi đang làm là:

- (void)changeState
{
     // Change state so cells are hidden/unhidden
     ...

    // Reload all sections
    NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];

    [tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView reloadData];
}

2
Ban phước cho em, người ngọt ngào ngọt ngào.
guptron

Bạn đã tìm thấy một giải pháp cho các trục trặc hoạt hình nhỏ? đối với tôi, các đường phân cách giữa các ô sẽ không hoạt động chính xác và id không sử dụng hình ảnh động nào hơn là một dòng bị lóa. giải pháp tuyệt vời mặc dù!
Maximilian Körner

Vấn đề của tôi là với các ô tĩnh numberOfRowsInSection:chỉ được gọi khi bảng tải lần đầu tiên. Khi tôi gọi [self.tableView reloadData] - numberOfRowsInSection:sẽ không bao giờ được gọi lại. Chỉ cellForRowAtIndexPath:được gọi. Tôi đang thiếu gì?
La Mã

13
  1. Trong trình thiết kế, tạo một lối thoát cho (các) ô bạn muốn ẩn. Ví dụ: bạn muốn ẩn 'cellOne', vì vậy, trong viewDidLoad () hãy làm điều này

cellOneOutlet.hidden = true

bây giờ ghi đè phương thức bên dưới, kiểm tra trạng thái ô nào bị ẩn và trả về chiều cao 0 cho các ô đó. Đây là một trong nhiều cách bạn có thể ẩn bất kỳ ô nào trong bảng tĩnh Xem nhanh.

override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat 
{

let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)

        if tableViewCell.hidden == true
        {
            return 0
        }
        else{
             return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
        }

}

Giải pháp tốt nhất cho đến nay!
derdida

thêm tableView.reloadData () sau khi thực hiện các thay đổi và nó hoàn hảo. Tiết kiệm cho tôi rất nhiều nỗ lực để thay đổi giải pháp! cảm ơn
Shaya C

1
Swift 4 không cho tôi sử dụng let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath). Tôi cho rằng nó được thay thế bởi let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath).
Clifton Labrum

Vì tôi đang sử dụng các ô tĩnh trên a UITableViewController, tôi không có bất kỳ UITableViewphương thức ủy nhiệm nào . Để có được nó để gọi heightForRow, tôi có cần phải có bất kỳ phương pháp nào khác không?
Clifton Labrum

@CliftonLabrum không, bạn chỉ có thể ghi đè phương thức này.
Alexander Ershov

11

Tôi đã đưa ra một giải pháp thay thế thực sự che giấu các phần và không xóa chúng. Tôi đã thử cách tiếp cận của @ henning77, nhưng tôi vẫn gặp vấn đề khi tôi thay đổi số phần của UITableView tĩnh. Phương pháp này đã làm việc rất tốt cho tôi, nhưng tôi chủ yếu cố gắng ẩn các phần thay vì các hàng. Tôi đang xóa một số hàng trên máy bay thành công, nhưng nó phức tạp hơn nhiều, vì vậy tôi đã cố gắng nhóm các thứ thành các phần mà tôi cần hiển thị hoặc ẩn. Đây là một ví dụ về cách tôi ẩn các phần:

Đầu tiên tôi khai báo một thuộc tính NSMutableArray

@property (nonatomic, strong) NSMutableArray *hiddenSections;

Trong viewDidLoad (hoặc sau khi bạn đã truy vấn dữ liệu của mình), bạn có thể thêm các phần bạn muốn ẩn vào mảng.

- (void)viewDidLoad
{
    hiddenSections = [NSMutableArray new];

    if(some piece of data is empty){
        // Add index of section that should be hidden
        [self.hiddenSections addObject:[NSNumber numberWithInt:1]];
    }

    ... add as many sections to the array as needed

    [self.tableView reloadData];
}

Sau đó thực hiện các phương thức ủy nhiệm TableView sau đây

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return nil;
    }

    return [super tableView:tableView titleForHeaderInSection:section];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        return 0;
    }

    return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        [cell setHidden:YES];
    }
}

Sau đó, đặt chiều cao của tiêu đề và chân trang thành 1 cho các phần bị ẩn vì bạn không thể đặt chiều cao thành 0. Điều này gây thêm không gian 2 pixel, nhưng chúng ta có thể bù cho nó bằng cách điều chỉnh chiều cao của tiêu đề hiển thị tiếp theo.

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
{
    CGFloat height = [super tableView:tableView heightForHeaderInSection:section];

    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        height = 1; // Can't be zero
    }
    else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
        // Adjust height for previous hidden sections
        CGFloat adjust = 0;

        for(int i = (section - 1); i >= 0; i--){
            if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
                adjust = adjust + 2;
            }
            else {
                break;
            }
        }

        if(adjust > 0)
        {                
            if(height == -1){
                height = self.tableView.sectionHeaderHeight;
            }

            height = height - adjust;

            if(height < 1){
                height = 1;
            }
        }
    }

    return height;
}

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 
{   
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return 1;
    }
    return [super tableView:tableView heightForFooterInSection:section];
}

Sau đó, nếu bạn có các hàng cụ thể để ẩn, bạn có thể điều chỉnh numberOfRowsInSection và hàng nào được trả về trong cellForRowAtIndexPath. Trong ví dụ này ở đây tôi có một phần có ba hàng trong đó bất kỳ ba hàng nào có thể trống và cần phải loại bỏ.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];

    if(self.organization != nil){
        if(section == 5){ // Contact
            if([self.organization objectForKey:@"Phone"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"Email"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"City"] == [NSNull null]){     
                rows--;
            }
        }
    }

    return rows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

Sử dụng offset IndexPath này để tính toán indexPath cho các hàng nơi bạn đang xóa các hàng một cách có điều kiện. Không cần thiết nếu bạn chỉ ẩn phần

- (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
{
    int row = indexPath.row;

    if(self.organization != nil){
        if(indexPath.section == 5){
            // Adjust row to return based on which rows before are hidden
            if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){     
                row = row + 2;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
        }
    }

    NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];

    return offsetPath;
}

Có rất nhiều phương pháp để ghi đè, nhưng điều tôi thích ở phương pháp này là nó có thể sử dụng lại được. Thiết lập mảng hiddenSections, thêm vào nó và nó sẽ ẩn các phần chính xác. Ẩn các hàng nó khó hơn một chút, nhưng có thể. Chúng ta không thể chỉ đặt chiều cao của các hàng mà chúng ta muốn ẩn thành 0 nếu chúng ta đang sử dụng UITableView được nhóm vì các đường viền sẽ không được vẽ chính xác.


1
Tôi có thể sẽ sử dụng NSMutableSetđể hiddenSectionsthay thế. Nó nhanh hơn rất nhiều vì bạn chủ yếu đang thử nghiệm thành viên.
pixelfreak

Câu trả lời tốt, Austin. Tôi đã bỏ phiếu trả lời và sẽ sử dụng nó làm tài liệu tham khảo cho các dự án của tôi trong tương lai. pixelfreak cũng đưa ra một quan điểm tốt về việc sử dụng NSMutableSetcho hiddenSections, mặc dù tôi hiểu rằng điểm của câu trả lời của bạn mang tính khái niệm hơn là kén chọn về việc bạn nên sử dụng loại cấu trúc dữ liệu nào.
BigSauce

10

Hóa ra, bạn có thể ẩn và hiển thị các ô trong UITableView tĩnh - và với hình ảnh động. Và nó không khó để thực hiện.

Dự án demo

Video dự án demo

Ý chính

  1. Use tableView:heightForRowAtIndexPath: để xác định chiều cao tế bào một cách linh hoạt dựa trên một số trạng thái.
  2. Khi trạng thái thay đổi các ô hiển thị / ẩn bằng cách gọi tableView.beginUpdates();tableView.endUpdates()
  3. Đừng gọi tableView.cellForRowAtIndexPath:bên trongtableView:heightForRowAtIndexPath: . Sử dụng indexPath được lưu trữ để phân biệt các ô.
  4. Đừng giấu tế bào. Thay vào đó, đặt thuộc tính "Clip Subview" trong Xcode.
  5. Sử dụng các ô tùy chỉnh (không phải Plain, v.v.) để có được một hình ảnh ẩn đẹp. Ngoài ra, xử lý Bố cục tự động chính xác cho trường hợp khi chiều cao ô == 0.

Thêm thông tin trong blog của tôi (tiếng Nga)


1
Điểm này rất quan trọng đối với tôi: "Không ẩn các ô. Thay vào đó, hãy đặt thuộc tính" Clip Subview "trong Xcode."
balkoth

8

Vâng, điều đó chắc chắn là có thể, mặc dù hiện tại tôi đang phải vật lộn với vấn đề tương tự. Tôi đã quản lý để có được các tế bào để ẩn và mọi thứ hoạt động tốt, nhưng hiện tại tôi không thể làm cho mọi thứ trở nên gọn gàng. Đây là những gì tôi đã tìm thấy:

Tôi đang ẩn các hàng dựa trên trạng thái của công tắc BẬT / TẮT ở hàng đầu tiên của phần đầu tiên. Nếu công tắc BẬT thì có 1 hàng bên dưới nó trong cùng một phần, nếu không thì có 2 hàng khác nhau.

Tôi có một bộ chọn được gọi khi công tắc được bật và tôi đặt một biến để cho biết tôi đang ở trạng thái nào. Sau đó, tôi gọi:

[[self tableView] reloadData];

Tôi ghi đè lên bảngView: willDisplayCell: forRowAtIndexPath: và nếu ô được cho là bị ẩn, tôi sẽ làm điều này:

[cell setHidden:YES];

Điều đó che giấu tế bào và nội dung của nó, nhưng không loại bỏ không gian mà nó chiếm giữ.

Để xóa khoảng trắng , ghi đè bảngView: heightForRowAtIndexPath: function và trả về 0 cho các hàng cần ẩn.

Bạn cũng cần ghi đè bảngView: numberOfRowsInSection: và trả về số lượng hàng trong phần đó. Bạn phải làm một cái gì đó kỳ lạ ở đây để nếu bảng của bạn là kiểu được nhóm, các góc tròn xuất hiện trên các ô chính xác. Trong bảng tĩnh của tôi có bộ ô đầy đủ cho phần, vì vậy có ô đầu tiên chứa tùy chọn, sau đó 1 ô cho các tùy chọn trạng thái BẬT và thêm 2 ô cho tùy chọn trạng thái TẮT, tổng cộng có 4 ô. Khi tùy chọn BẬT, tôi phải trả về 4, điều này bao gồm tùy chọn ẩn để tùy chọn cuối cùng được hiển thị có hộp tròn. Khi tùy chọn tắt, hai tùy chọn cuối cùng không được hiển thị để tôi quay lại 2. Tất cả đều cảm thấy lộn xộn. Xin lỗi nếu điều này không rõ ràng, thật khó để mô tả. Chỉ để minh họa cho việc thiết lập, đây là cấu trúc của phần bảng trong IB:

  • Hàng 0: Tùy chọn với công tắc BẬT / TẮT
  • Hàng 1: Hiển thị khi tùy chọn BẬT
  • Hàng 2: Hiển thị khi tùy chọn TẮT
  • Hàng 3: Hiển thị khi tùy chọn TẮT

Vì vậy, khi tùy chọn BẬT, bảng báo cáo hai hàng đó là:

  • Hàng 0: Tùy chọn với công tắc BẬT / TẮT
  • Hàng 1: Hiển thị khi tùy chọn BẬT

Khi tùy chọn TẮT, bảng báo cáo bốn hàng đó là:

  • Hàng 0: Tùy chọn với công tắc BẬT / TẮT
  • Hàng 1: Hiển thị khi tùy chọn BẬT
  • Hàng 2: Hiển thị khi tùy chọn TẮT
  • Hàng 3: Hiển thị khi tùy chọn TẮT

Cách tiếp cận này không cảm thấy đúng vì nhiều lý do, theo như tôi đã có với thử nghiệm của mình cho đến nay, vì vậy xin vui lòng cho tôi biết nếu bạn tìm thấy một cách tốt hơn. Các vấn đề tôi đã quan sát cho đến nay là:

  • Cảm thấy sai khi nói với bảng số lượng hàng khác với những gì có lẽ chứa trong dữ liệu cơ bản.

  • Tôi dường như không thể làm sống động sự thay đổi. Tôi đã thử sử dụng tableView: reloadSections: withRowAnimation: thay vì reloadData và kết quả dường như không có ý nghĩa, tôi vẫn đang cố gắng để làm việc này. Hiện tại những gì dường như xảy ra là bảngView không cập nhật các hàng chính xác, do đó, một hàng vẫn bị ẩn sẽ được hiển thị và một khoảng trống được để lại dưới hàng đầu tiên. Tôi nghĩ rằng điều này có thể liên quan đến điểm đầu tiên về dữ liệu cơ bản.

Hy vọng rằng ai đó sẽ có thể đề xuất các phương pháp thay thế hoặc có lẽ làm thế nào để mở rộng với hoạt hình, nhưng có lẽ điều này sẽ giúp bạn bắt đầu. Tôi xin lỗi vì thiếu liên kết đến các chức năng, tôi đã đặt chúng vào nhưng chúng bị bộ lọc thư rác từ chối vì tôi là người dùng khá mới.


Tôi khá chắc chắn rằng bạn nên gọi [[self tableView] reloadData];thêm một lần nữa sau khi ẩn các ô
Shmidt

Xin lỗi để làm sống lại điều này, nhưng làm thế nào bạn có thể phân lớp UITableViewControll và sử dụng nó với các ô tĩnh? Xcode sẽ không cho tôi.
Dany Joumaa

Không, bạn không cần phải phân lớp UITableView. Trong bảng phân cảnh, chọn TableViewControll của bạn, sau đó nhấp vào TableView. Bây giờ bạn có thể chọn giữa các ô động / tĩnh.
Shmidt

1
Tôi tìm thấy giải pháp làm thế nào để làm động các ô tĩnh ẩn / hiển thị. Chỉ cần gọi return [super tableView:tableView cellForRowAtIndexPath:indexPath];trong UITableViewControllerlớp con để tạo các ô tĩnh. Đường dẫn chỉ mục được lập chỉ mục tĩnh - không động ...
k06a

8

Theo câu trả lời của Justas, nhưng đối với Swift 4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = super.tableView(tableView, cellForRowAt: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAt: indexPath)
}

1
bạn có thể cần tableView.reloadRows(at:, with:)cập nhật các ô nếu bạn thay đổi chiều cao trong khi hàng đã hiển thị.
Frost-Lee

5

Được rồi, sau một số cố gắng, tôi có một câu trả lời không phổ biến. Tôi đang sử dụng biến "isHidden" hoặc "hidden" để kiểm tra xem ô này có bị ẩn hay không.

  1. tạo một IBOutlet để bộ điều khiển xem của bạn. @IBOutlet weak var myCell: UITableViewCell!

  2. Cập nhật myCellchức năng tùy chỉnh của bạn, ví dụ bạn có thể thêm nó trong viewDidLoad:

override func viewDidLoad() { super.viewDidLoad() self.myCell.isHidden = true }

  1. trong phương thức đại biểu của bạn:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = super.tableView(tableView, cellForRowAt: indexPath) guard !cell.isHidden else { return 0 } return super.tableView(tableView, heightForRowAt: indexPath) }

Điều này sẽ làm giảm logic của bạn trong phương thức ủy nhiệm và bạn chỉ cần tập trung vào yêu cầu kinh doanh của mình.


4

Các câu trả lời ở trên ẩn / hiển thị các ô, thay đổi hàngHeight hoặc lộn xộn với các ràng buộc bố cục Tự động không phù hợp với tôi vì các vấn đề về bố cục Tự động. Các mã trở nên không thể chịu đựng được.

Đối với một bảng tĩnh đơn giản, điều làm việc tốt nhất với tôi là:

  1. Tạo một lối thoát cho mọi ô trong bảng tĩnh
  2. Tạo một mảng chỉ với các đầu ra của các ô để hiển thị
  3. Ghi đè cellForRowAtIndexPath để trả về ô từ mảng
  4. Ghi đè sốOfRowsInSection để trả về số lượng của mảng
  5. Thực hiện một phương thức để xác định những ô nào cần có trong mảng đó và gọi phương thức đó bất cứ khi nào cần, sau đó tải lạiData.

Đây là một ví dụ từ bộ điều khiển xem bảng của tôi:

@IBOutlet weak var titleCell: UITableViewCell!
@IBOutlet weak var nagCell: UITableViewCell!
@IBOutlet weak var categoryCell: UITableViewCell!

var cellsToShow: [UITableViewCell] = []

override func viewDidLoad() {
    super.viewDidLoad()
    determinCellsToShow()
}

func determinCellsToShow() {
    if detail!.duration.type != nil {
        cellsToShow = [titleCell, nagCell, categoryCell]
    }
    else {
        cellsToShow = [titleCell,  categoryCell]
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    return cellsToShow[indexPath.row]
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return cellsToShow.count
}

Điều này làm việc rất tốt, thậm chí 5 năm sau! Cảm ơn bạn rất nhiều.
Schrockwell

2020 và đây là giải pháp lớn nhất cho việc này. Không cần hack.
mdonati

3

Phương pháp tương thích iOS 11 & IB / Storyboard đơn giản

Đối với iOS 11, tôi thấy rằng phiên bản sửa đổi của câu trả lời của Mohamed Saleh hoạt động tốt nhất, với một số cải tiến dựa trên tài liệu của Apple. Nó hoạt hình độc đáo, tránh mọi hack xấu hoặc giá trị được mã hóa cứng và sử dụng chiều cao hàng đã được đặt trong Trình tạo giao diện .

Khái niệm cơ bản là đặt chiều cao của hàng thành 0 cho bất kỳ hàng ẩn nào. Sau đó sử dụng tableView.performBatchUpdatesđể kích hoạt một hình ảnh động hoạt động nhất quán.

Đặt chiều cao ô

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath == indexPathOfHiddenCell {
        if cellIsHidden {
            return 0
        }
    }
    // Calling super will use the height set in your storyboard, avoiding hardcoded values
    return super.tableView(tableView, heightForRowAt: indexPath)
}

Bạn sẽ muốn đảm bảo cellIsHiddenindexPathOfHiddenCellđược đặt phù hợp với trường hợp sử dụng của bạn. Đối với mã của tôi, chúng là các thuộc tính trên bộ điều khiển xem bảng của tôi.

Vượt qua tế bào

Trong bất kỳ phương thức nào, điều khiển mức độ hiển thị (có thể là hành động của nút hoặc didSelectRow), chuyển trạng thái cellIsHidden, bên trong một performBatchUpdateskhối:

tableView.performBatchUpdates({
                // Use self to capture for block
                self.cellIsHidden = !self.cellIsHidden 
            }, completion: nil)

Apple khuyến nghị performBatchUpdateshơn beginUpdates/endUpdates bất cứ khi nào có thể.


1

Tôi tìm thấy một giải pháp cho các ô ẩn ẩn hoạt hình trong bảng tĩnh.

// Class for wrapping Objective-C block
typedef BOOL (^HidableCellVisibilityFunctor)();
@interface BlockExecutor : NSObject
@property (strong,nonatomic) HidableCellVisibilityFunctor block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
@end
@implementation BlockExecutor
@synthesize block = _block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
{
    BlockExecutor * executor = [[BlockExecutor alloc] init];
    executor.block = block;
    return executor;
}
@end

Chỉ cần thêm một từ điển:

@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end

Và nhìn vào việc thực hiện MyTableViewControll. Chúng ta cần hai phương thức để chuyển đổi indexPath giữa các chỉ mục hữu hình và vô hình ...

- (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row <= indexPath.row + rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
}

- (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row < indexPath.row - rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
}

Một IBAction về thay đổi giá trị UISwitch:

- (IBAction)birthdaySwitchChanged:(id)sender
{
    NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
    if (self.birthdaySwitch.on)
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    else
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

Một số phương thức UITableViewDataSource và UITableViewDelegate:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
    for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
        if (indexPath.section == section)
        {
            BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
            numberOfRows -= (executor.block()?0:1);
        }
    return numberOfRows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // initializing dictionary
    self.hidableCellsDict = [NSMutableDictionary dictionary];
    [self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}

- (void)viewDidUnload
{
    [self setBirthdaySwitch:nil];
    [super viewDidUnload];
}

@end

1

Trả lời nhanh chóng :

Thêm phương thức sau vào TableViewControll của bạn:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

nếu bảngView cố gắng vẽ ô bạn muốn ẩn, thì nó sẽ không hiển thị nó vì chiều cao của nó sẽ được đặt thành 0pt nhờ vào phương thức trên, mọi thứ khác vẫn không thay đổi.

Xin lưu ý rằng indexPathOfCellYouWantToHidecó thể thay đổi bất cứ lúc nào :)


1

Trong> Swift 2.2, tôi đã kết hợp một vài câu trả lời ở đây.

Tạo một lối thoát từ bảng phân cảnh để liên kết đến staticCell của bạn.

@IBOutlet weak var updateStaticCell: UITableViewCell!

override func viewDidLoad() {
    ...
    updateStaticCell.hidden = true
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if indexPath.row == 0 {
        return 0
    } else {
        return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
    }
}

Tôi muốn ẩn ô đầu tiên của mình để đặt chiều cao về 0 như mô tả ở trên.


1

Swift 4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    var height = super.tableView(tableView, heightForRowAt: indexPath)
    if (indexPath.row == HIDDENROW) {
        height = 0.0
    }
    return height
}

0

Đối với kịch bản dễ nhất khi bạn ẩn các ô ở cuối chế độ xem bảng, bạn có thể điều chỉnh nội dung của bảng xem sau khi bạn ẩn ô:

- (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
{
    CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
    self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
}


0

Giải pháp từ k06a ( https://github.com/k06a/ABStaticTableViewContoder ) tốt hơn vì nó ẩn toàn bộ phần bao gồm các tiêu đề và chân trang của ô, trong đó giải pháp này ( https://github.com/peterpaulis/StaticDataTableViewContoder ) ẩn mọi thứ trừ chân trang.

BIÊN TẬP

Tôi chỉ tìm giải pháp nếu bạn muốn ẩn chân trang StaticDataTableViewController. Đây là những gì bạn cần sao chép trong tệp StaticTableViewControll.m:

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
    if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
        return nil;
    } else {
        return [super tableView:tableView titleForFooterInSection:section];
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

    CGFloat height = [super tableView:tableView heightForFooterInSection:section];

    if (self.originalTable == nil) {
        return height;
    }

    if (!self.hideSectionsWithHiddenRows) {
        return height;
    }

    OriginalSection * os = self.originalTable.sections[section];
    if ([os numberOfVissibleRows] == 0) {
       //return 0;
        return CGFLOAT_MIN;
    } else {
        return height;
    }

    //return 0;
    return CGFLOAT_MIN;
}

0

Chắc chắn bạn có thể. Trước tiên, hãy quay lại bảng của bạn Số lượng ô bạn muốn hiển thị sau đó gọi superđể đạt được một số ô nhất định từ bảng phân cảnh của bạn và trả lại cho bảng Xem:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.mode.numberOfCells()
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))

    return cell
}

Nếu các ô của bạn có hieght khác, hãy trả lại:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}

0

Ngoài giải pháp @Saleh Masum:

Nếu bạn gặp lỗi tự động bố trí , bạn có thể xóa các ràng buộc khỏitableViewCell.contentView

Swift 3:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)

    if tableViewCell.isHidden == true
    {
        tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
        return 0
    }
    else{
        return super.tableView(tableView, heightForRowAt: indexPath)
    }

}

Giải pháp này phụ thuộc vào lưu lượng của ứng dụng của bạn . Nếu bạn muốn hiển thị / ẩn ô trong cùng thể hiện của trình điều khiển khung nhìn thì đây có thể không phải là lựa chọn tốt nhất, vì nó loại bỏ các ràng buộc .


0

Tôi có một cách tốt hơn để ẩn các ô tĩnh và thậm chí các phần động mà không có bất kỳ hack nào.

Đặt chiều cao hàng thành 0 có thể ẩn một hàng, nhưng điều đó không hiệu quả nếu bạn muốn ẩn toàn bộ phần sẽ giữ một số khoảng trống ngay cả khi bạn ẩn tất cả các hàng.

Cách tiếp cận của tôi là xây dựng một mảng các ô tĩnh. Sau đó, nội dung xem bảng sẽ được điều khiển bởi mảng phần.

Đây là một số mã mẫu:

var tableSections = [[UITableViewCell]]()

private func configTableSections() {
    // seciton A
    tableSections.append([self.cell1InSectionA, self.cell2InSectionA])

    // section B
    if shouldShowSectionB {
        tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
    }

    // section C
    if shouldShowCell1InSectionC {
        tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
    } else {
        tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
    }
}

func numberOfSections(in tableView: UITableView) -> Int {
    return tableSections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tableSections[section].count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    return tableSections[indexPath.section][indexPath.row]
}

Bằng cách này, bạn có thể đặt tất cả các mã cấu hình của mình lại với nhau mà không phải viết mã khó chịu để tính số lượng hàng và phần. Và tất nhiên, không0 chiều cao nữa.

Mã này cũng rất dễ duy trì. Ví dụ: nếu bạn muốn thêm / xóa nhiều ô hoặc phần.

Tương tự, bạn có thể tạo một mảng tiêu đề phần tiêu đề và mảng tiêu đề chân trang phần để cấu hình tiêu đề phần của bạn một cách linh hoạt.

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.