Câu trả lời:
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
IBOutletCollection
như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ũ.
Để ẩn các ô tĩnh trong UITable:
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ó:
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. ;-)
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à.
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. UITableViewController
là 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 UITableViewController
và 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];
}
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ì?
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)
}
}
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)
.
UITableViewController
, tôi không có bất kỳ UITableView
phươ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?
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.
NSMutableSet
để hiddenSections
thay thế. Nó nhanh hơn rất nhiều vì bạn chủ yếu đang thử nghiệm thành viên.
NSMutableSet
cho 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.
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.
Ý chính
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.tableView.beginUpdates();tableView.endUpdates()
tableView.cellForRowAtIndexPath:
bên trongtableView:heightForRowAtIndexPath:
. Sử dụng indexPath được lưu trữ để phân biệt các ô.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:
Vì vậy, khi tùy chọn BẬT, bảng báo cáo hai hàng đó là:
Khi tùy chọn TẮT, bảng báo cáo bốn hàng đó là:
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.
[[self tableView] reloadData];
thêm một lần nữa sau khi ẩn các ô
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
trong UITableViewController
lớ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 ...
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)
}
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ị.
Đượ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.
tạo một IBOutlet để bộ điều khiển xem của bạn.
@IBOutlet weak var myCell: UITableViewCell!
Cập nhật myCell
chứ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
}
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.
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à:
Đâ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 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.
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 cellIsHidden
và indexPathOfHiddenCell
đượ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.
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 performBatchUpdates
khối:
tableView.performBatchUpdates({
// Use self to capture for block
self.cellIsHidden = !self.cellIsHidden
}, completion: nil)
Apple khuyến nghị performBatchUpdates
hơn beginUpdates
/endUpdates
bất cứ khi nào có thể.
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
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 indexPathOfCellYouWantToHide
có thể thay đổi bất cứ lúc nào :)
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.
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
}
Đố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);
}
Đây là cách mới để thực hiện việc này bằng cách sử dụng https://github.com/k06a/ABStaticTableViewControll
NSIndexPath *ip = [NSIndexPath indexPathForRow:1 section:1];
[self deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade]
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;
}
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))
}
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 .
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.