Аккордеонная ячейка таблицы - Как динамически расширять/сокращать uitableviewcell?

Я пытаюсь создать аккордеонный тип uitableviewcell, который, когда пользователь выбирает ячейку, расширяется, чтобы отобразить подробный инфо-просмотр, аналогичный тому, как работает приложение digg. Сначала я попытался заменить текущую таблицу на пользовательскую ячейку в cellForRowAtIndex, однако анимация выглядит немного изменчивой, поскольку вы можете видеть заменяемую ячейку, и в целом эффект не работает хорошо.

Если вы посмотрите на приложение digg и другие, которые сделали это, кажется, что они arent заменяют текущую ячейку, но вместо этого, возможно, добавляют subview в ячейку? Исходная ячейка, однако, не кажется вообще живой, и только новые аккордеоны в таблице.

Есть ли у кого-нибудь идеи, как добиться подобного эффекта?

Update: Я сделал некоторый прогресс, используя метод neha ниже, и пока ячейка анимирует правильный путь, он разрушает хаос с другими ячейками в таблице. То, что я сделал, является подклассом UITableViewCell с пользовательским классом, который содержит экземпляр UIView, который на самом деле рисует представление, которое затем добавляю к содержимому содержимого ячеек таблицы.

- (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;           
} 

Теперь кажется, что ячейка расширяется, но на самом деле не обновляется, поэтому отображаются метки и текстовые поля. Однако они появляются, когда я прокручиваю ячейку и на экране.

Любые идеи?

Ответ 1

Способы использования Apple довольно просты.

Сначала вам нужно сохранить выбранную строку 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 для выбранной ячейки.

Теперь мы можем вернуться к обновлениям начала и конца. Этот блок вызывает перезагрузку всей геометрии таблицы. Более того, этот блок анимирован, что в конечном итоге дает импрессия строки расширения.

Надеюсь, это было полезно, Pawel

Ответ 2

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

Если вы не хотите перезагружать ячейку (вы хотите сохранить свою существующую ячейку и просто изменить размер и, вероятно, добавить/удалить некоторые подзаголовки), тогда просто выполните трюк beginUpdates/endUpdates в файле didSelectRowAtIndexPath:, и вызовите некоторый метод в вашей ячейке, чтобы вызвать изменение макета. beginUpdates/endUpdates предложит tableView повторно запросить высоты для каждой ячейки - так что верните правильное значение.

Ответ 3

Создайте класс, который подклассы UITableviewcell в вашем проекте. Создайте этот класс 'nib и установите его родительский класс в свой проект с помощью tableview и переопределите его -

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

Запишите методы contractCell() и expandCell() в этом классе и укажите высоту ячеек, которые вы хотите использовать в методе expandCell. Вызовите эти методы соответствующим образом на основе некоторых флагов, установленных для идентификации, когда ячейка находится в расширенном состоянии или состоянии контракта. Используйте таблицу tableview

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

для обработки выбранных ячеек.

Ответ 4

Замените функцию 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

создать массив wof-словаря, у которого есть ключ Select_sts, который равен 0 в начале при нажатии на его изменение 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];

}