你可以在UITableViewCell上select一个高度变化的animation吗?
我在我的iPhone应用程序中使用UITableView
,我有一个属于一个组的人的列表。 我希望这样,当用户点击一个特定的人(从而select单元格)时,单元格高度增长,以显示用于编辑该人的属性的多个UI控件。
这可能吗?
我发现一个真正简单的解决scheme,作为我正在研究的UITableView
的副作用…..
通过tableView: heightForRowAtIndexPath:
将单元格高度存储在一个通常会报告原始高度的variables中,然后当您想要设置高度变化的animation时,只需更改variables的值并调用这个…
[tableView beginUpdates]; [tableView endUpdates];
你会发现它并没有完全重新加载,但足以让UITableView
知道它必须重新绘制单元格,抓住单元格的新高度值,并猜测是什么? 它dynamic改变你。 甜。
我有更详细的解释和完整的代码示例在我的博客… Animate UITableView细胞高度变化
我喜欢Simon Lee的回答。 我没有真的尝试这种方法,但它看起来会改变列表中所有单元格的大小。 我希望只是改变了被挖掘的细胞。 我有点像西蒙,但只是有点区别。 当它被选中时,这将改变单元格的外观。 它有animation。 只是另一种方式来做到这一点。
创build一个int来保存当前所选单元格索引的值:
int currentSelection;
然后:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; selectedNumber = row; [tableView beginUpdates]; [tableView endUpdates]; }
然后:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if ([indexPath row] == currentSelection) { return 80; } else return 40; }
我相信你可以在tableView:cellForRowAtIndexPath中做类似的改变:改变单元格的types,甚至为单元格加载一个xib文件。
像这样,currentSelection将从0开始。如果您不希望列表中的第一个单元(在索引0处)默认为选中状态,则需要进行调整。
添加一个属性来跟踪选定的单元格
@property (nonatomic) int currentSelection;
将其设置为(例如) viewDidLoad
,以确保UITableView
以“正常”位置开始
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. //sentinel self.currentSelection = -1; }
在heightForRowAtIndexPath
您可以设置所需单元格的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ int rowHeight; if ([indexPath row] == self.currentSelection) { rowHeight = self.newCellHeight; } else rowHeight = 57.0f; return rowHeight; }
在didSelectRowAtIndexPath
,保存当前select并保存dynamic高度(如果需要)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // do things with your cell here // set selection self.currentSelection = indexPath.row; // save height for full text label self.newCellHeight = cell.titleLbl.frame.size.height + cell.descriptionLbl.frame.size.height + 10; // animate [tableView beginUpdates]; [tableView endUpdates]; } }
在didDeselectRowAtIndexPath
将select索引设置回标记值,并将单元格恢复为正常forms
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { // do things with your cell here // sentinel self.currentSelection = -1; // animate [tableView beginUpdates]; [tableView endUpdates]; } }
reloadData不好,因为没有animation…
这是我目前正在尝试:
NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]; [self.tableView beginUpdates]; [self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade]; [self.tableView deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade]; [self.tableView endUpdates];
它几乎是正确的。 几乎。 我正在增加单元格的高度,有时在表格视图中有一个小小的“打嗝”,因为单元格被replace,就好像表格视图中的一些滚动位置正在被保留一样,新的单元格(它是第一个单元格在表中)的偏移过高,并且滚动视图反弹以重新定位它。
我用reloadRowsAtIndexPaths
解决了。
我保存在didSelectRowAtIndexPath
所选单元格的indexPath,并在最后调用reloadRowsAtIndexPaths
(你可以发送NSMutableArray的元素的列表,你想要重新加载)。
在heightForRowAtIndexPath
您可以检查indexPath是否在expandIndexPath单元格的列表中并且发送高度。
你可以检查这个基本的例子: https : //github.com/ferminhg/iOS-Examples/tree/master/iOS-UITableView-Cell-Height-Change/celdascambiadetam这是一个简单的解决scheme。
如果帮助你,我添加一些代码
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 20; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath*)indexPath { if ([indexPath isEqual:_expandIndexPath]) return 80; return 40; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Celda"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; [cell.textLabel setText:@"wopwop"]; return cell; } #pragma mark - #pragma mark Tableview Delegate Methods - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSMutableArray *modifiedRows = [NSMutableArray array]; // Deselect cell [tableView deselectRowAtIndexPath:indexPath animated:TRUE]; _expandIndexPath = indexPath; [modifiedRows addObject:indexPath]; // This will animate updating the row sizes [tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic]; }
我不知道所有关于调用beginUpdates / endUpdates的东西是什么,你可以使用-[UITableView reloadRowsAtIndexPaths:withAnimation:]
。 这是一个示例项目 。
只是像我这样的人寻找添加“更多细节”自定义单元的说明。
[tableView beginUpdates]; [tableView endUpdates];
做了一个出色的工作,但不要忘记“收割”细胞的观点。 从界面生成器中select你的单元格 – >内容视图 – >属性检查器select“ 剪辑子视图 ”
试试这是为了扩展索引行:
@property (nonatomic) NSIndexPath *expandIndexPath; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { if ([indexPath isEqual:self.expandedIndexPath]) return 100; return 44; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSMutableArray *modifiedRows = [NSMutableArray array]; if ([indexPath isEqual:self.expandIndexPath]) { [modifiedRows addObject:self.expandIndexPath]; self.expandIndexPath = nil; } else { if (self.expandedIndexPath) [modifiedRows addObject:self.expandIndexPath]; self.expandIndexPath = indexPath; [modifiedRows addObject:indexPath]; } // This will animate updating the row sizes [tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic]; // Preserve the deselection animation (if desired) [tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; [tableView deselectRowAtIndexPath:indexPath animated:YES]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ViewControllerCellReuseIdentifier]; cell.textLabel.text = [NSString stringWithFormat:@"I'm cell %ld:%ld", (long)indexPath.section, (long)indexPath.row]; return cell; }
BOOL flag; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { flag = !flag; [tableView beginUpdates]; [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView endUpdates]; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return YES == flag ? 20 : 40; }
西蒙·李的答案迅速版本。
// MARK: - Variables var isCcBccSelected = false // To toggle Bcc. // MARK: UITableViewDelegate func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { // Hide the Bcc Text Field , until CC gets focused in didSelectRowAtIndexPath() if self.cellTypes[indexPath.row] == CellType.Bcc { if (isCcBccSelected) { return 44 } else { return 0 } } return 44.0 }
然后在didSelectRowAtIndexPath()
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { self.tableView.deselectRowAtIndexPath(indexPath, animated: true) // To Get the Focus of CC, so that we can expand Bcc if self.cellTypes[indexPath.row] == CellType.Cc { if let cell = tableView.cellForRowAtIndexPath(indexPath) as? RecipientTableViewCell { if cell.tag == 1 { cell.recipientTypeLabel.text = "Cc:" cell.recipientTextField.userInteractionEnabled = true cell.recipientTextField.becomeFirstResponder() isCcBccSelected = true tableView.beginUpdates() tableView.endUpdates() } } } }
这里是我自定义的UITableView
子类的代码,它在表格单元格中展开UITextView
,而无需重新加载(并丢失键盘焦点):
- (void)textViewDidChange:(UITextView *)textView { CGFloat textHeight = [textView sizeThatFits:CGSizeMake(self.width, MAXFLOAT)].height; // Check, if text height changed if (self.previousTextHeight != textHeight && self.previousTextHeight > 0) { [self beginUpdates]; // Calculate difference in height CGFloat difference = textHeight - self.previousTextHeight; // Update currently editing cell's height CGRect editingCellFrame = self.editingCell.frame; editingCellFrame.size.height += difference; self.editingCell.frame = editingCellFrame; // Update UITableView contentSize self.contentSize = CGSizeMake(self.contentSize.width, self.contentSize.height + difference); // Scroll to bottom if cell is at the end of the table if (self.editingNoteInEndOfTable) { self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + difference); } else { // Update all next to editing cells NSInteger editingCellIndex = [self.visibleCells indexOfObject:self.editingCell]; for (NSInteger i = editingCellIndex; i < self.visibleCells.count; i++) { UITableViewCell *cell = self.visibleCells[i]; CGRect cellFrame = cell.frame; cellFrame.origin.y += difference; cell.frame = cellFrame; } } [self endUpdates]; } self.previousTextHeight = textHeight; }
我使用了@ Joy的真棒答案,并且与ios 8.4和XCode 7.1.1完美配合。
如果您正在寻找使您的单元格切换,我改变了-tableViewDidSelect为以下内容:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ //This is the bit I changed, so that if tapped once on the cell, //cell is expanded. If tapped again on the same cell, //cell is collapsed. if (self.currentSelection==indexPath.row) { self.currentSelection = -1; }else{ self.currentSelection = indexPath.row; } // animate [tableView beginUpdates]; [tableView endUpdates]; }
我希望这些帮助你。
在iOS 7及更高版本之后检查此方法。
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{ return UITableViewAutomaticDimension; }
iOS 8已经对此进行了改进。我们可以将其设置为表视图本身的属性。
是的,这是可能的。
UITableView
有一个委托方法didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [UIView animateWithDuration:.6 delay:0 usingSpringWithDamping:UIViewAnimationOptionBeginFromCurrentState initialSpringVelocity:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ cellindex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section]; NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil]; [violatedTableView beginUpdates]; [violatedTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationAutomatic]; [violatedTableView endUpdates]; } completion:^(BOOL finished) { }]; }
但在你的情况下,如果用户滚动和select一个不同的单元格,那么你需要让最后选中的单元格缩小并展开当前选中的单元格reloadRowsAtIndexPaths:
调用heightForRowAtIndexPath:
如此处理。
下面是对Swift 3的较短版本的Simons答案。还允许切换单元格的select
var cellIsSelected: IndexPath? func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { cellIsSelected = cellIsSelected == indexPath ? nil : indexPath tableView.beginUpdates() tableView.endUpdates() } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if cellIsSelected == indexPath { return 250 } return 65 }
获取所选行的索引path。 重新加载表格。 在UITableViewDelegate的heightForRowAtIndexPath方法中,将所选行的高度设置为不同的高度,其他行将返回正常的行高
我刚刚解决了这个问题,一点点黑客:
static int s_CellHeight = 30; static int s_CellHeightEditing = 60; - (void)onTimer { cellHeight++; [tableView reloadData]; if (cellHeight < s_CellHeightEditing) heightAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(onTimer) userInfo:nil repeats:NO] retain]; } - (CGFloat)tableView:(UITableView *)_tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (isInEdit) { return cellHeight; } cellHeight = s_CellHeight; return s_CellHeight; }
当我需要扩大单元格高度时,我设置了isInEdit = YES
并调用方法[self onTimer]
,它[self onTimer]
单元格的增长,直到达到s_CellHeightEditing值:-)
您可以使用此方法并根据需要更改返回值
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 71; }