回答:
私はこれに対する本当に簡単な解決策を、UITableView
私が取り組んでいる副作用として見つけました...
通常はを介して元の高さを報告する変数にセルの高さtableView: heightForRowAtIndexPath:
を保存し、高さの変化をアニメーション化する場合は、変数の値を変更してこれを呼び出します...
[tableView beginUpdates];
[tableView endUpdates];
あなたはそれが完全なリロードを行わないことがわかりますが、それがUITableView
セルを再描画し、セルの新しい高さの値を取得する必要があることを知るのに十分です...そして何を推測しますか?それはあなたのために変化をアニメートします。甘い。
ブログに詳細な説明と完全なコードサンプルがあります... UITableViewセルの高さの変化をアニメーション化
You can also use this method followed by the endUpdates method to animate the change in the row heights without reloading the cell.
developer.apple.com/library/ios/documentation/UIKit/Reference/...
サイモン・リーの答えが好きです。実際にはその方法を試していませんが、リスト内のすべてのセルのサイズが変わるようです。タップした細胞だけの交換を期待していた。私はちょっとサイモンのようにそれをやったが、少しだけ違いました。選択すると、セルの外観が変わります。そして、それはアニメーション化します。それを行うためのちょうど別の方法。
現在選択されているセルインデックスの値を保持する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:でも同様の変更を加えて、セルのタイプを変更したり、セルの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
、あなたの現在の選択を保存し、必要に応じて、動的な高さを保存
- (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
センチネル値の選択指標バックを設定し、正規形への細胞バックをアニメート
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
// do things with your cell here
// sentinel
self.currentSelection = -1;
// animate
[tableView beginUpdates];
[tableView endUpdates];
}
}
アニメーションがないためreloadDataは適切ではありません...
これは私が現在試していることです:
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];
ほとんど問題なく動作します。ほとんど。セルの高さを増やしており、セルが置き換えられると、テーブルビューにスクロールの位置が保持されているように、新しいセル(最初のセル)テーブル内)は、オフセットが高すぎる状態になり、スクロールビューが跳ね返って再配置されます。
beginUpdates / endUpdatesを連続して呼び出すことに関するすべてのことは何なのかわかりません-[UITableView reloadRowsAtIndexPaths:withAnimation:]
。単にを使用できます。これがプロジェクトの例です。
で解決しましたreloadRowsAtIndexPaths
。
didSelectRowAtIndexPath
選択したセルのindexPath に保存し、reloadRowsAtIndexPaths
最後に呼び出します(リロードする要素のリストのNSMutableArrayを送信できます)。
に heightForRowAtIndexPath
indexPathがリストにあるかどうかexpandIndexPathセルのとセンド・高さのかどうかをチェックすることができます。
この基本的な例を確認できます:https : //github.com/ferminhg/iOS-Examples/tree/master/iOS-UITableView-Cell-Height-Change/celdascambiadetam これは簡単なソリューションです。
私があなたを助けるなら、私は一種のコードを追加します
- (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()
、推奨される呼び出しは次のとおりです。
tableView.performBatchUpdates(nil, completion: nil)
Appleは、beginUpdates / endUpdatesに関して、「可能な限り、このメソッドの代わりにperformBatchUpdates(_:completion :)メソッドを使用する」と述べています。
参照:https : //developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates
これをインデックスごとの行を拡張するために試してください:
@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;
}
カスタムセルに「詳細」を追加することを検索している私のような人への単なるメモ。
[tableView beginUpdates];
[tableView endUpdates];
すばらしい作品でしたが、セルビューを「トリミング」することを忘れないでください。Interface Builderからセルを選択->コンテンツビュー->プロパティインスペクターから " Clip subview "を選択
短いバージョンのSimonsがSwift 3に回答します。セルの選択を切り替えることもできます
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
}
Simon Leeの回答のSwiftバージョン。
// 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
デリゲートメソッドがあります 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) {
}];
}
しかし、あなたの場合、ユーザーがスクロールして別のセルを選択した場合、現在選択されているセルのreloadRowsAtIndexPaths:
呼び出しを縮小および展開するには、最後に選択されたセルを使用する必要があるため、heightForRowAtIndexPath:
それに応じて処理します。
リロードせずに(そしてキーボードフォーカスを失って)テーブルセル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];
}
これがお役に立てば幸いです。
Simon Leeの回答の Swiftバージョン:
tableView.beginUpdates()
tableView.endUpdates()
高さプロパティを変更する前に 変更する必要があることに注意してくださいendUpdates()
。
入力-
tableView.beginUpdates()tableView.endUpdates() これらの関数は呼び出しません
func tableView(_ tableView:UITableView、cellForRowAt indexPath:IndexPath)-> UITableViewCell {}
ただし、その場合、 tableView.reloadRows(at:[selectedIndexPath!as IndexPath]、with:.none)
func tableView(_ tableView:UITableView、cellForRowAt indexPath:IndexPath)-> UITableViewCell {} この関数を呼び出し ます。
私はちょっとしたハックでこの問題を解決しました:
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]
を呼び出し、s_CellHeightEditing値に達するまでセルの成長をアニメーション化します:-)
選択された行のインデックスパスを取得します。テーブルをリロードします。UITableViewDelegateのheightForRowAtIndexPathメソッドで、選択した行の高さを別の高さに設定し、その他の場合は通常の行の高さを返します
[table reloadData]
を行うと、アニメーション化するのではなく、即座に高さの変化が起こります。