2010-06-17 50 views
56

我想創建一個手風琴類型的uitableviewcell,當用戶選擇單元格時,它展開顯示一個類似於digg應用程序的內嵌詳細信息視圖。我最初嘗試用cellForRowAtIndex中的customcell替換當前的tablecell,但是動畫看起來有點波濤洶涌,因爲您可以看到被替換的單元格,並且整體效果不能很好地工作。Accordion table cell - 如何動態擴展/收縮uitableviewcell?

如果你看看digg應用程序和其他誰做了這個似乎他們不是取代當前的單元格,而是可能添加一個子視圖到單元格?然而,原始單元格似乎根本不具有動畫效果,只有新的視圖才能進入表格。

有沒有人有任何想法如何實現類似的效果?

更新: 我一直在使用下面NEHA的方法,而小區動畫它肆虐,在表中的其他細胞的正確的方式取得了一些進展。我所做的是將UITableViewCell與包含UIView實例的自定義類進行子類化,該實例實際上繪製了視圖,然後將其添加到表格單元格contentview。

- (void)setSelected:(BOOL)selected animated:(BOOL)animated { 

if (selected) { 
    [self expandCell]; 
} 
} 

-(void)expandCell { 
    self.contentView.frame = CGRectMake(0.0, 0.0, self.contentView.bounds.size.width, 110); 
} 

這裏是所有表委託方法我使用:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

if (isSearching && indexPath.row == selectedIndex) { 

    static NSString *CellIdentifier = @"SearchCell"; 
    CustomTableCell *cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
    } 

    [cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]]; 

    UILabel *theText = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 10.0, cell.contentView.bounds.size.width -20, 22.0)]; 
    theText.text = @"Title Text"; 
    [cell.contentView addSubview:theText]; 


    UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10 + 46.0, cell.contentView.bounds.size.width - 20, 40.0)]; 
    textField.borderStyle = UITextBorderStyleLine; 
    [cell.contentView addSubview:textField];   

    UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(5.0, 88.0, cell.contentView.bounds.size.width - 20, 22.0)]; 
    testLabel.text = [NSString stringWithFormat:@"Some text here"]; 
    [cell.contentView addSubview:testLabel]; 

    [theText release]; 
    [textField release]; 
    [testLabel release]; 

    return cell;   
} else { 

    static NSString *CellIdentifier = @"Cell"; 
    CustomTableCell *cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
    } 

    [cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]]; 
    return cell; 
} 


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

[tableView deselectRowAtIndexPath:indexPath animated:NO]; 

selectedIndex = indexPath.row; 
isSearching = YES; 


[tableView beginUpdates]; 
[tableView endUpdates]; 

} 


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {   
if (isSearching && indexPath.row == selectedIndex) { 
    return 110; 
} 
return rowHeight;   
} 

現在看來,該小區正在擴大,但實際上沒有被刷新,從而被的arent所示的標籤和文本框。但是,當我將單元格關閉並在屏幕上滾動時,它們會顯示出來。

任何想法?

+0

人時?不是在尋找詳細的代碼,而只是關於如何實現這一目標的一些指導方針? – 2010-06-18 04:06:18

+0

你爲什麼不讓帕維爾的答案是正確的答案......你不能比這更好。 – 2013-11-15 03:52:27

回答

2

在您的項目中創建一個UITableviewcell的子類。創建這個類的筆尖,並設置其母公司爲與實現代碼如下項目中的類,並覆蓋其 -

(void)setSelected:(BOOL)selected animated:(BOOL)animated 

寫入方法contractCell()和expandCell()在這個類,並提供細胞的高度你想要在expandCell方法中。基於一些標誌設置來適當調用這些方法,以識別單元處於展開狀態還是收縮狀態。使用你的tableview的

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

處理單元格選擇的方法。

+0

neha,thx爲您的反應。你能詳細解釋一下如何去做這件事嗎?我仍然有點困惑如何使用setSelected:方法?在調用expandCell/contractCell後,tableCell會自動調整它的高度,更重要的是,它會顯示爲選中的單元格正在展開,而不是簡單地重新加載,這是我遇到的最初問題?我在didSelectRowAtIndex中調用了reoloadRowsAtIndex,並且在工作時,您可以直觀地看到正在重新加載的單元格,無論是從頂部/底部/等。取決於所選的動畫風格。 – 2010-06-19 06:01:36

+0

創建一個子類爲uitablviewcell的類後,方法「(void)setSelected:(BOOL)selected animated:(BOOL)animated」會自動出現在創建的類中,只要您在tableview中選擇一個單元格,就會明確地調用該類。它用於配置單元格的選定狀態的視圖。確保還要創建這個uitableviewcell子類的一個筆尖,並將此筆尖的父母設置爲您的tableview類。是的,這會給你你期待的效果,它會顯示細胞擴大/收縮,而不是重新加載。 – neha 2010-06-19 12:07:45

+0

嗨neha,thx再次回覆。我似乎正在取得一些進展,但請參閱上面我已經嘗試過的更改和問題,我仍然有。另外什麼代碼應該進入setSelected:方法?仍然試圖通過這個遺憾不幸。 thx – 2010-06-20 05:36:28

92

蘋果的方法很簡單。

首先,你需要保存選定indexPath行:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    self.selectedRowIndex = [indexPath retain]; 
    [tableView beginUpdates]; 
    [tableView endUpdates]; 
} 

稍後我將解釋的開始/結束時更新的一部分。

然後,當你有當前選擇的索引,你可以告訴tableView它應該給這行更多的空間。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    //check if the index actually exists 
    if(selectedRowIndex && indexPath.row == selectedRowIndex.row) { 
     return 100; 
    } 
    return 44; 
} 

這將返回所選單元格的高度100。

現在我們可以回到開始/結束更新。該塊觸發所有tableView幾何的重新加載。而且,該塊是動畫的,最終給出了行擴展的印象。

希望這是有幫助的, 帕維爾

+0

hi Pawel,試過這個,動畫的影響正是我所尋找的,但問題我碰到的是,這段代碼不會調用cellForRowAtIndex,所以我無法弄清楚如何/在哪裏修改擴展單元格的內容。它只是調整單元格的高度。我也嘗試通過以下方式獲取didSelectRowAtIndex中的單元格: UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath]; 並更改單元格,然後調用beginUpdates。雖然這起作用,但似乎對桌子的其餘部分造成嚴重破壞。你能解釋一下你對選中的單元格進行修改以避免這種情況嗎? – 2010-06-19 16:46:08

+5

由於您正在調用didSelectCellForRowAtIndexPath:方法中的開始/結束更新,因此該單元格已被選中。因此,您可以使用單元實現中的setSelected:animated:方法將其配置爲選定狀態。 – Pawel 2010-06-20 11:09:04

+0

嗨,我更新了我的代碼以上反映了一些這些變化,但似乎如果我把代碼創建新的內容,如標籤,textfields等到cellForRowAtIndex方法,那麼它不工作,因爲該方法不會被調用時你可以調用[tableView beginUpdate]和[tableView endUpdates]。所以我不知道該把代碼放在哪裏以及如何正確使用setSelected:方法?任何意見都會讓我發瘋。 – 2010-06-20 21:52:33

0

與此一替換您的cellForRowAtIndexPath功能。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath 
*)indexPath { 

    if (isSearching && indexPath.row == selectedIndex) { 

     static NSString *CellIdentifier = @"SearchCell"; 
     CustomTableCell *cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 

     [cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]]; 

     UILabel *theText = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 
10.0, cell.contentView.bounds.size.width 
-20, 22.0)]; 
     theText.text = @"Title Text"; 
     [cell.contentView addSubview:theText]; 


     UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10 + 
46.0, cell.contentView.bounds.size.width - 20, 40.0)]; 
     textField.borderStyle = UITextBorderStyleLine; 
     [cell.contentView addSubview:textField];   

     UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(5.0, 
88.0, cell.contentView.bounds.size.width - 20, 22.0)]; 
     testLabel.text = [NSString stringWithFormat:@"Some text here"]; 
     [cell.contentView addSubview:testLabel]; 

     [theText release]; 
     [textField release]; 
     [testLabel release]; 

     return cell;   
    } else { 

     static NSString *CellIdentifier = @"Cell"; 
     CustomTableCell *cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 

     [cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]]; 
     return cell; 
    } 
    } 
5

Pawel的beginUpdates/endUpdates技巧很好,我經常使用它。但在這種情況下,您只需重新加載正在更改狀態的行,確保您正確地使用所需的單元格類型重新加載它們,並返回正確的新單元格高度。

這裏是什麼,我覺得你要完成一個完整的工作實現:

.H:

#import <UIKit/UIKit.h> 

@interface ExpandingTableViewController : UITableViewController 
{ 

} 

@property (retain) NSIndexPath* selectedIndexPath; 

@end 

.M:

@implementation ExpandingTableViewController 
@synthesize selectedIndexPath; 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    // Return the number of sections. 
    return 1; 
} 


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    // Return the number of rows in the section. 
    return 10; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    static NSString *CellIdentifier1 = @"Cell1"; 
    static NSString *CellIdentifier2 = @"Cell2"; 

    UITableViewCell *cell; 

    NSIndexPath* indexPathSelected = self.selectedIndexPath; 

    if (nil == indexPathSelected || [indexPathSelected compare: indexPath] != NSOrderedSame) 
    { 
     cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1]; 
     if (cell == nil) { 
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1] autorelease]; 
     } 

     cell.textLabel.text = [NSString stringWithFormat: @"cell %d", indexPath.row]; 
    } 
    else 
    { 
     cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2]; 
     if (cell == nil) { 
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier2] autorelease]; 
     } 

     cell.textLabel.text = [NSString stringWithFormat: @"cell %d", indexPath.row]; 
     cell.detailTextLabel.text = [NSString stringWithFormat: @"(expanded!)", indexPath.row]; 
    } 

    return cell; 
} 

#pragma mark - 
#pragma mark Table view delegate 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (self.selectedIndexPath != nil && [self.selectedIndexPath compare: indexPath] == NSOrderedSame) 
    { 
     return tableView.rowHeight * 2; 
    } 

    return tableView.rowHeight; 
} 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSArray* toReload = [NSArray arrayWithObjects: indexPath, self.selectedIndexPath, nil]; 
    self.selectedIndexPath = indexPath; 

    [tableView reloadRowsAtIndexPaths: toReload withRowAnimation: UITableViewRowAnimationMiddle]; 
} 


#pragma mark - 
#pragma mark Memory management 

- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 
} 

- (void)viewDidUnload { 
} 

- (void)dealloc { 
    [super dealloc]; 
} 

@end 

如果你不這樣做想要重新加載單元格(您希望保留現有單元格並更改大小,並且可能會添加/刪除某些子視圖),那麼只需執行didSelectRowAtIndexPath中的beginUpdates/endUpdates技巧即可:我在你的單元格方法煽動佈局的變化。 beginUpdates/endUpdates將提示tableView重新查詢每個單元格的高度 - 所以一定要返回正確的值。

-1

創建其中有一個關鍵Select_sts這在開局0陣列WOF字典點擊它的變化1 accourdingü改變表

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ 

    customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 40.0)]; 
    UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 
    headerLabel.backgroundColor = [UIColor clearColor]; 
    headerLabel.opaque = NO; 
    headerLabel.textColor = [UIColor blackColor]; 
    headerLabel.highlightedTextColor = [UIColor whiteColor]; 
    headerLabel.font = [UIFont boldSystemFontOfSize:16]; 
    headerLabel.frame = CGRectMake(5.0, 10.0, 300.0, 20.0); 
    headerLabel.text=[NSString stringWithFormat: @"PNR %@",[[record objectAtIndex:section] objectForKey:@"number"]]; 
    customView.backgroundColor=[UIColor whiteColor]; 

btn_openClose.tag=section+10000; 
    btn_openClose.backgroundColor=[UIColor clearColor]; 
    // [btn_openClose setImage:[UIImage imageNamed:@"down_arrow.png"] forState:UIControlStateNormal]; 
    [btn_openClose addTarget:self action:@selector(collapseExpandButtonTap:) forControlEvents:UIControlEventTouchUpInside]; 
    [customView addSubview:btn_openClose]; 

} 


- (void) collapseExpandButtonTap:(id) sender{ 
    int indexNo=[sender tag]-10000; 
// NSLog(@"total_record %@",[total_record objectAtIndex:indexNo]); 
    NSMutableDictionary *mutDictionary = [[total_record objectAtIndex:indexNo] mutableCopy]; 
    if([[mutDictionary objectForKey:@"Select_sts"] integerValue]==0) 
     [mutDictionary setObject:[NSNumber numberWithInt:1] forKey:@"√"]; 
    else 
     [mutDictionary setObject:[NSNumber numberWithInt:0] forKey:@"Select_sts"]; 

    [total_record replaceObjectAtIndex:indexNo withObject:mutDictionary]; 

// [table_view beginUpdates]; 
// [table_view reloadData]; 
// [table_view endUpdates]; 

    NSMutableIndexSet *indetsetToUpdate = [[NSMutableIndexSet alloc]init]; 
    [indetsetToUpdate addIndex:indexNo]; // [indetsetToUpdate addIndex:<#(NSUInteger)#>] 
    // You can add multiple indexes(sections) here. 
    [table_view reloadSections:indetsetToUpdate withRowAnimation:UITableViewRowAnimationFade]; 

}