UITableView
设置为静态单元格。
是否可以通过编程的方式隐藏其中一些单元格?
UITableView
设置为静态单元格。
是否可以通过编程的方式隐藏其中一些单元格?
隐藏UITable中的静态单元格:
在您的UITableView控制器代理类中:
Objective-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];
}
Swift:
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)
}
这种方法会为UITable中的每个单元格调用。一旦它为您想要隐藏的单元格调用了它,我们就将其高度设置为0。我们通过为目标单元格创建一个outlet来识别目标单元格:
https://github.com/xelvenone/StaticDataTableViewController
这个功能可以展示/隐藏/重新加载任何静态单元格,可以选择是否使用动画效果!
[self cell:self.outletToMyStaticCell1 setHidden:hide];
[self cell:self.outletToMyStaticCell2 setHidden:hide];
[self reloadDataAnimated:YES];
setHidden
方法)。 - Jack最好的方法如下面博客所述:http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/
像平常在interface builder中设计静态表视图一样完成所有潜在隐藏单元格的设计。但是,有一件事情必须为每个想要隐藏的单元格做 - 检查单元格的“剪裁子视图”属性,否则当您尝试隐藏单元格(通过缩小其高度 - 更多细节可见于后面)时,单元格的内容不会消失。
所以,你有一个开关在一个单元格中,这个开关应该隐藏和显示一些静态单元格。将它与一个IBAction连接,然后在其中执行以下操作:
[self.tableView beginUpdates];
[self.tableView endUpdates];
这可以为出现和消失的单元格提供漂亮的动画效果。现在实现以下表视图委托方法:
- (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;
}
就是这样。转动开关,单元格就会隐现,并带有一个漂亮流畅的动画效果。
我的解决方案与Gareth类似,虽然我做了一些不同的事情。
具体如下:
1. 隐藏单元格
没有直接隐藏单元格的方法。 UITableViewController
是提供静态单元格的数据源,目前还没有办法告诉它“不要提供单元格x”。
因此,我们必须提供自己的数据源,该数据源委托UITableViewController
以获取静态单元格。
最简单的方法是子类化UITableViewController
,并覆盖需要在隐藏单元格时表现不同的所有方法。
在最简单的情况下(单节表格,所有单元格具有相同的高度),可以按照以下方式进行:
- (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];
}
如果您的表格有多个部分或单元格高度不同,则需要覆盖更多的方法。相同的原则适用于此处:在委托给 super 之前,您需要偏移 indexPath、section 和 row。didSelectRowAtIndexPath:
这样的方法,indexPath 参数会因状态(即隐藏的单元格数)而导致同一单元格产生不同的值。因此,通常最好偏移任何 indexPath 参数并使用这些值进行操作。reloadSections:withRowAnimation:
方法来动画显示更改,将会出现严重的故障。reloadData:
,动画效果会大大改善(只剩下轻微的故障)。动画后,表格会正确显示。- (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:
仅在表格第一次加载时调用。当我调用 [self.tableView reloadData] 时,numberOfRowsInSection:
永远不会再次被调用。只有 cellForRowAtIndexPath:
被调用。我错过了什么吗? - RomancellOneOutlet.hidden = true
现在覆盖下面的方法,检查哪个单元格状态被隐藏并返回高度0。这是在Swift中隐藏静态tableView中任何单元格的众多方法之一。
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)
。我猜它被let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath)
替换了。 - Clifton LabrumUITableViewController
上使用静态单元格,因此我没有任何UITableView
委托方法。为了让它调用heightForRow
,我还需要其他方法吗? - Clifton LabrumtableView:heightForRowAtIndexPath:
根据某些状态动态指定单元格高度。tableView.beginUpdates();tableView.endUpdates()
来使单元格动画显示/隐藏。tableView:heightForRowAtIndexPath:
中调用tableView.cellForRowAtIndexPath:
。使用缓存的indexPaths来区分单元格。@property (nonatomic, strong) NSMutableArray *hiddenSections;
- (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];
}
- (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];
}
}
将头部和尾部的高度设置为1,以隐藏部分,因为无法将高度设置为0。这会导致额外的2像素空间,但是我们可以通过调整下一个可见标题的高度来弥补这个问题。
-(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];
}
如果您确实有需要隐藏的特定行,则可以调整numberOfRowsInSection和在cellForRowAtIndexPath中返回哪些行。在这个例子中,我有一个部分有三行,其中任何三行都可能为空并需要被删除。
- (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]];
}
- (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;
}
有很多覆盖方法,但我喜欢这种方法的可重用性。设置hiddenSections数组,添加到其中,它将隐藏正确的部分。隐藏行有点棘手,但是可以实现。如果我们使用分组的UITableView,我们不能仅将要隐藏的行的高度设置为0,因为边框将无法正确绘制。
NSMutableSet
来代替hiddenSections
。因为它更快,而你大多数时候只是在测试成员资格。 - pixelfreakNSMutableSet
,尽管我理解你的答案更多地是概念性的,而不是挑剔哪种类型的数据结构应该使用。 - BigSauce根据Justas的回答,但适用于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:)
来更新这些单元格。 - Frost-Lee[[self tableView] reloadData];
[cell setHidden:YES];
因此,当选项为 ON 时,表格报告的两行是:
当选项关闭时,表格报告的四行是:
这种方法之所以不正确,原因有几个,这只是我迄今为止的实验结果,请让我知道是否有更好的方法。到目前为止,我观察到的问题有:
告诉表格行数与底层数据中的行数不同感觉不对。
我似乎无法动画显示更改。我尝试使用 tableView:reloadSections:withRowAnimation: 而不是 reloadData,但结果似乎不合理,我仍在努力让它工作。目前似乎发生的情况是 tableView 没有更新正确的行,因此一个应该显示的行仍然隐藏,而第一行下留下了一个空白。我认为这可能与底层数据的第一点有关。
希望有人能够提出替代方法或者如何扩展动画,但也许这会让您有所启示。很抱歉没有超链接到函数,我加入了它们,但由于我是一个相对较新的用户,它们被垃圾邮件过滤器拒绝了。
[[self tableView] reloadData];
。 - Shmidtreturn [super tableView:tableView cellForRowAtIndexPath:indexPath];
即可。索引路径是静态索引,而非动态的... - k06a好的,在尝试一些方法后,我有一个非常规的答案。我使用“isHidden”或“hidden”变量来检查此单元格是否应该隐藏。
为您的视图控制器创建一个IBOutlet。
@IBOutlet weak var myCell: UITableViewCell!
在您的自定义函数中更新myCell
,例如您可以在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)
}
这将简化您的委托方法中的逻辑,您只需要专注于业务需求即可。
ClipToBounds
问题,您也可以将单元格设置为隐藏。这样看起来更加清晰简洁。;-) - MonsieurDart