programing

선택하면 UITableViewCell에서 높이 변경을 애니메이션화할 수 있습니까?

stoneblock 2023. 6. 13. 21:57

선택하면 UITableViewCell에서 높이 변경을 애니메이션화할 수 있습니까?

사용 중입니다.UITableView내 아이폰 앱에서, 그리고 나는 그룹에 속한 사람들의 목록을 가지고 있습니다.사용자가 특정 사용자를 클릭하면(따라서 셀을 선택하면) 셀의 높이가 커져 해당 사용자의 속성을 편집하기 위한 여러 UI 컨트롤이 표시되도록 하면 좋겠습니다.

이것이 가능합니까?

저는 이것에 대한 정말 간단한 해결책을 찾았습니다.UITableView저는 작업을 하고 있었습니다...

셀 높이를 변수에 저장합니다. 변수는 일반적으로 다음을 통해 원래 높이를 보고합니다.tableView: heightForRowAtIndexPath:그런 다음 높이 변경을 애니메이션화하려면 변수 값을 변경하고 이를 호출합니다.

[tableView beginUpdates];
[tableView endUpdates];

전체 다시 로드는 수행하지 않지만 다음을 수행하기에 충분하다는 것을 알게 될 것입니다.UITableView세포를 다시 그려야 한다는 것을 알기 위해서는 세포의 새로운 높이 값을 잡아야 합니다. 그리고 무엇을 맞혀보세요?그것은 당신을 위해 변화를 애니메이션화합니다.달콤해.

블로그에 더 자세한 설명과 전체 코드 샘플이 있습니다.UI 테이블 보기 셀 높이 변경 애니메이션화

저는 사이먼 리의 답변이 마음에 듭니다.저는 실제로 그 방법을 시도하지는 않았지만 목록에 있는 모든 셀의 크기를 바꿀 것으로 보입니다.저는 도청되는 세포만 바뀌기를 바라고 있었습니다.저는 사이먼처럼 했지만 약간의 차이만 있었습니다.셀을 선택하면 셀 모양이 변경됩니다.그리고 그것은 생명력이 있습니다.또 다른 방법입니다.

현재 선택한 셀 인덱스의 값을 유지할 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 파일을 로드할 수도 있습니다.

이와 같이 현재 선택은 0에서 시작됩니다.목록의 첫 번째 셀(색인 0)이 기본적으로 선택된 것처럼 보이지 않도록 하려면 조정해야 합니다.

선택한 셀을 추적할 속성 추가

@property (nonatomic) int currentSelection;

에서 sentinel 값으로 설정합니다(예: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];
    }
}

에 에.beginUpdates()/endUpdates()권장 통화 내용은 다음과 같습니다.

tableView.performBatchUpdates(nil, completion: nil)

Apple은 beginUpdates/endUpdates와 관련하여 "가능하면 항상 이 메서드 대신 performBatchUpdates(_:completion:) 메서드를 사용하십시오."라고 말합니다.

참조: https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates

애니메이션이 없기 때문에 데이터를 다시 로드할 수 없습니다...

제가 현재 시도하고 있는 것은 다음과 같습니다.

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하고 "인덱스Path"를 합니다.reloadRowsAtIndexPaths(재로드할 요소의 목록을 위해 NSMutableArray를 전송할 수 있습니다).

heightForRowAtIndexPath셀 및 heightexpandIndexPath 셀 할 수 .

다음과 같은 기본적인 예를 확인할 수 있습니다. 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];
}

스위프트 4 이상

아래 코드를 테이블 보기의 didselect 행 위임 방법에 추가

tableView.beginUpdates()
tableView.setNeedsLayout()
tableView.endUpdates()

인덱스별 행을 확장할 때 사용합니다.

@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에서 Cell -> Content View -> Property Inspector에서 "Clip subview"를 선택합니다.

여기 스위프트 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
  }

사이먼 리의 답변의 빠른 버전.

// 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
}

그러면 indid SelectRowAt인덱스 경로()

  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:따라서 그에 따라 처리합니다.

이 제 입니다.UITableViewsubclass,하는 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에서 이 기능이 개선되었습니다.테이블 뷰 자체의 속성으로 설정할 수 있습니다.

사이먼 리의 답변의 빠른 버전:

tableView.beginUpdates()
tableView.endUpdates()

높이 속성을 수정해야 합니다. endUpdates().

입력 -

tableView.beginUpdates() tableView.endUpdates() 이 함수는 호출하지 않습니다.

funcableView(_tableView: UITableView, cellForRowAtindexPath: IndexPath) -> UITableViewCell {}

그러나 이 경우 tableView.reloadRows(위치: [선택됨]IndexPath! as IndexPath](인덱스Path!)(.none 포함)

함수 테이블View(_tableView: UITableView, cellForRowAtindexPath: 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 그 을 그고방을부릅다니법리▁the다부라고 부릅니다.[self onTimer] 값에 :-).

선택한 행의 인덱스 경로를 가져옵니다.테이블을 다시 로드합니다.행 높이에서UITableViewDelegate의 IndexPath 메서드는 선택한 행의 높이를 다른 높이로 설정하고 다른 행의 경우 일반 행 높이를 반환합니다.

언급URL : https://stackoverflow.com/questions/460014/can-you-animate-a-height-change-on-a-uitableviewcell-when-selected