변경할 때 UITableView에 대한 reloadData에 애니메이션을 적용하십시오.


183

두 가지 모드가있는 UITableView가 있습니다. 모드 간을 전환하면 섹션마다 다른 수의 섹션과 셀이 있습니다. 이상적으로는 테이블이 커지거나 줄어들 때 멋진 애니메이션을 만듭니다.

여기에 내가 시도한 코드가 있지만 아무것도하지 않습니다.

CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5]; 

[self.tableView reloadData];
[UIView commitAnimations];

내가 어떻게 할 수 있을지에 대한 생각?

답변:


400

실제로 매우 간단합니다.

[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

에서 문서 :

이 메소드를 호출하면 테이블보기가 데이터 소스에 지정된 섹션에 대한 새 셀을 요청합니다. 테이블 뷰는 기존 셀을 애니메이션 처리 할 때 새 셀 삽입을 애니메이션합니다.


13
그리고이 페이지에서 가장 좋은 대답!
Matthias D

41
첫 번째 섹션 만 다시로드하기 때문에 이것은 완전히 올바른 것은 아닙니다. 테이블에 여러 섹션이 있으면 작동하지 않습니다.
Nosrettap

4
데이터가 변경되지 않은 경우 예외가 발생할 수 있습니다. 내 답변보기
Matej

8
@Nosrettap : 더 갖고 싶어 나있는 tableView를 다시로드의 모든 섹션, 당신이해야 할 모든 요구 사항이 아니라 갱신 할 것을, 모든 섹션 인덱스로 NSIndexSet을 확장하다
JonEasy

스위프트 버전 : _tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Fade)특히, 첫 번째 섹션 인 섹션 0 만 업데이트합니다.
kbpontius

264

다음을 사용할 수 있습니다.

목표 -C

[UIView transitionWithView: self.tableView
                  duration: 0.35f
                   options: UIViewAnimationOptionTransitionCrossDissolve
                animations: ^(void)
 {
      [self.tableView reloadData];
 }
                completion: nil];

빠른

UIView.transitionWithView(tableView,
                          duration: 0.35,
                          options: .TransitionCrossDissolve,
                          animations:
{ () -> Void in
    self.tableView.reloadData()
},
                          completion: nil);

스위프트 3, 4 및 5

UIView.transition(with: tableView,
                  duration: 0.35,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() }) // left out the unnecessary syntax in the completion block and the optional completion parameter

번거 로움이 없습니다. :디

UIViewAnimationOptionTransitions더 차가운 효과를 위해 원하는 것을 사용할 수도 있습니다 .

  • transitionNone
  • transitionFlipFromLeft
  • transitionFlipFromRight
  • transitionCurlUp
  • transitionCurlDown
  • transitionCrossDissolve
  • transitionFlipFromTop
  • transitionFlipFromBottom

2
테이블 뷰의 시작 / 종료 상태가 매우 다르고 (추가 / 제거 할 섹션과 행을 계산하는 것이 복잡 할 경우) 유용하지만 애니메이션이되지 않은 재로드보다 덜 방해가되는 부분이 있습니다.
벤 패커드

1
내장 된 메소드를 사용하여 테이블 뷰를 다시로드하는 것만 큼 좋은 애니메이션은 아니지만 여기에 언급 된 높은 등급의 방법과 달리이 섹션은 여러 섹션이있을 때 작동합니다.
Mark Bridges

1
와우 모든 나머지를 시도한 후에 이것은 나를 위해 완벽하게 완벽하다
Lucas Goossen

1
@MarkBridges 더 높은 등급의 답변은 여러 섹션에서 작동합니다 :)[_tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] withRowAnimation:UITableViewRowAnimationFade];
lobianco

2
@Anthony 종료 상태에 시작 상태보다 많거나 적은 섹션이 있으면 작동하지 않습니다. 그런 다음 추가 / 삭제 된 섹션을 수동으로 추적해야하는데 이는 매우 번거 롭습니다.
nikolovski

78

CATransition수업을 통해 더 많은 자유를 누리십시오.

페이딩에만 국한되지는 않지만 움직임도 가능합니다.


예를 들면 다음과 같습니다.

(가져 오기를 잊지 마십시오 QuartzCore)

CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.fillMode = kCAFillModeForwards;
transition.duration = 0.5;
transition.subtype = kCATransitionFromBottom;

[[self.tableView layer] addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];

등을 type필요에 맞게 변경하십시오 kCATransitionFade.

스위프트에서의 구현 :

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.5
transition.subtype = kCATransitionFromTop
self.tableView.layer.addAnimation(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

CATransition에 대한 참조

스위프트 5 :

let transition = CATransition()
transition.type = CATransitionType.push
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.fillMode = CAMediaTimingFillMode.forwards
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromTop
self.tableView.layer.add(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

이는 단일 행 / 섹션 대신 테이블 전체를 애니메이션합니다.
Agos

@Agos 여전히 질문에 대답합니다. "한 행만 다시로드하는 방법"이라는 질문에는 애니메이션을의 layer속성에 적용하는 것과 같은 다른 대답 이 UITableViewCell있습니다.
Matej

@matejkramny 나는 테이블이 다른 행 (애니메이션에서 참조 된 것처럼)에만 애니메이션을 줄 것으로 기대했지만이 방법은 모든 테이블을 한 번에 푸시합니다. 어쩌면 내가 뭔가를 놓치고 있습니까?
Agos

@Agos 흠 아니 그렇게해야합니다. QuartzCore가 뷰를 직접 수정하므로 테이블의 절반 만 수행 할 수 없습니다. 테이블보기에서 셀을 가져 와서이 애니메이션을 각각에 적용 해 볼 수는 있지만 작동하지는 않습니다.
Matej

2
kCATransitionFade의 매력처럼 작동했습니다! :)
quarezz

60

데이터 구조를 업데이트하면 다음과 같습니다.

[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];

또한 "withRowAnimation"은 부울이 아니라 애니메이션 스타일입니다.

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle

간단한 물건이지만 너무 쉽게 스택 오버플로로 이동하여 트롤 문서보다 필요한 스 니펫을 얻을 수 있습니다. . 감사!
재스퍼 블루스

24

이 모든 답변은 하나의 섹션으로 UITableView를 사용한다고 가정합니다.

섹션이 두 개 이상인 상황을 정확하게 처리하려면 다음을 사용하십시오.

NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

(참고 : 섹션이 0 개 이상 있는지 확인해야합니다!)

이 코드로 데이터 소스를 동시에 업데이트하려고하면 NSInternalInconsistencyException이 발생할 수 있습니다. 이 경우 다음과 유사한 논리를 사용할 수 있습니다.

int sectionNumber = 0; //Note that your section may be different

int nextIndex = [currentItems count]; //starting index of newly added items

[myTableView beginUpdates];

for (NSObject *item in itemsToAdd) {
    //Add the item to the data source
    [currentItems addObject:item];

    //Add the item to the table view
    NSIndexPath *path = [NSIndexPath indexPathForRow:nextIndex++ inSection:sectionNumber];
    [myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationAutomatic];
}

[myTableView endUpdates];

3
섹션 계산에 대한 좋은 지적이지만 섹션이 하나 뿐이고 코드에 오류가 있습니다. 코드의 첫 줄을 NSRange range = NSMakeRange (0, myTableView.numberOfSections)로 변경해야했습니다.
Danyal Aytekin

18

이것에 접근하는 방법은 tableView에게 행과 섹션을 제거하고 추가하도록 지시하는 것입니다.

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation:
deleteSections:withRowAnimation:

UITableView의 메소드.

이 메소드를 호출하면 테이블이 요청한 항목을 애니메이션 처리 한 다음 reloadData 자체를 호출하여이 애니메이션 이후의 상태를 업데이트 할 수 있습니다. 이 부분은 중요합니다. 모든 것을 애니메이션 처리하지만 테이블의 dataSource에서 반환 된 데이터를 변경하지 않으면 애니메이션이 완료된 후 행이 다시 나타납니다.

따라서 응용 프로그램 흐름은 다음과 같습니다.

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

테이블의 dataSource 메소드가 검사 [self tableIsInSecondState](또는 무엇이든) 하여 올바른 새로운 섹션 및 행 세트를 반환하는 한 원하는 결과를 얻을 수 있습니다.


16

최고 답변에 대해서는 언급 할 수 없지만 신속한 구현은 다음과 같습니다.

self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)

reloadSections의 첫 번째 인수에 업데이트하려는 섹션을 포함 할 수 있습니다.

문서에서 사용할 수있는 다른 애니메이션 : https://developer.apple.com/reference/uikit/uitableviewrowanimation

페이드 삽입되거나 삭제 된 행은 테이블 뷰에서 페이드 인 또는 페이드 아웃됩니다.

오른쪽 삽입 된 행을 오른쪽에서 밀어 넣습니다. 삭제 된 행이 오른쪽으로 미끄러 져 나옵니다.

왼쪽 삽입 된 행을 왼쪽에서 밀어 넣습니다. 삭제 된 행은 왼쪽으로 미끄러 져 나옵니다.

top 삽입 된 행을 맨 위에서 밀어 넣습니다. 삭제 된 행은 위쪽으로 미끄러 져 나옵니다.

bottom 삽입 된 행을 아래쪽에서 밀어 넣습니다. 삭제 된 행은 아래쪽으로 미끄러 져 나옵니다.

case none 삽입되거나 삭제 된 행이 기본 애니메이션을 사용합니다.

middle 테이블 뷰는 이전 및 새 셀을 그들이 차지했거나 차지할 공간의 중앙에 유지하려고합니다. iPhone 3.2에서 사용할 수 있습니다.

자동 테이블보기는 적절한 애니메이션 스타일을 선택합니다. (iOS 5.0에서 도입되었습니다.)


1
Swift 4.2의 경우 : self.tableView.reloadSections ([0], with UITableView.RowAnimation.fade)
Reefwing

14

@ dmarnel 답변 스위프트 4 버전 :

tableView.reloadSections(IndexSet(integer: 0), with: .automatic)

9

신속한 구현 :

let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)

8

대한 스위프트 4

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)

1

필자의 경우 테이블 뷰에 10 개의 행을 추가하고 ( "결과 더보기"기능 유형) 다음을 수행했습니다.

  NSInteger tempNumber = self.numberOfRows;
  self.numberOfRows += 10;
  NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
  for (NSInteger i = tempNumber; i < self.numberOfRows; i++) {
    [arrayOfIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
  }
  [self.tableView beginUpdates];
  [self.tableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
  [self.tableView endUpdates];

대부분의 경우 "self.numberOfRows"대신 일반적으로 테이블 뷰에 대한 객체 배열 수를 사용합니다. 따라서이 솔루션이 제대로 작동하려면 "arrayOfIndexPaths"는 삽입되는 행의 인덱스 경로에 대한 정확한 배열이어야합니다. 이 인덱스 경로에 대해 행이 존재하면 코드가 충돌 할 수 있으므로 충돌을 피하기 위해 해당 인덱스 경로에 대해 "reloadRowsAtIndexPaths : withRowAnimation :"메소드를 사용해야합니다.


1

UITableView 셀에 사용자 정의 애니메이션을 추가하려면

[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];

보이는 셀의 배열을 얻을 수 있습니다. 그런 다음 각 셀에 사용자 정의 애니메이션을 추가하십시오.

매끄러운 커스텀 셀 애니메이션을 위해 게시 한이 요점을 확인하십시오. https://gist.github.com/floprr/1b7a58e4a18449d962bd


1

Swift 에서 reloadData ()없이 애니메이션 은 다음과 같이 수행 할 수 있습니다 (버전 2.2 기준).

tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
    // ...or here, if you need to add/remove the same amount of objects to/from somewhere
    indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
    numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()

애니메이션이 끝난 후 reloadData ()를 호출해야하는 경우 다음과 같이 CATransaction의 변경 사항을 수용 할 수 있습니다.

CATransaction.begin()
CATransaction.setCompletionBlock({() in self.tableview.reloadData() })
tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove.count ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
     // ...or here, if you need to add/remove the same amount of objects to/from somewhere
     indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
     numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()
CATransaction.commit()

행을 삭제하는 경우에 대한 논리가 표시되지만 행을 추가하는 경우에도 동일한 아이디어가 작동합니다. 애니메이션을 UITableViewRowAnimation.Left로 변경하여 깔끔하게 만들거나 사용 가능한 다른 애니메이션 목록에서 선택할 수도 있습니다.


1
CATransition *animation = [CATransition animation];
animation.duration = .3;
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setDuration:.3];

[[_elementTableView layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

[tableView reloadData];

2
왜 지속 시간을 .3두 번 설정 합니까?
Pang

1

사용자 정의 기간이있는 섹션 뿐만 아니라 모든 섹션다시로드합니다 .

사용자 정의 기간을 설정하기위한 사용자 duration매개 변수입니다 UIView.animate.

UIView.animate(withDuration: 0.4, animations: { [weak self] in
    guard let `self` = self else { return }
    let indexSet = IndexSet(integersIn: 0..<self.tableView.numberOfSections)
    self.tableView.reloadSections(indexSet, with: UITableView.RowAnimation.fade)
})

0

UITableView스위프트의 기본 애니메이션

tableView.performBatchUpdates이 동시에 발생하도록 행을 한 번에 삽입하고 삭제하십시오 . 다음과 같은 @ iKenndac 사용 방법의 대답을 바탕으로합니다.

  • tableView.insertSections
  • tableView.insertRows
  • tableView.deleteSections
  • tableView.deleteRows

전의:

 tableView.performBatchUpdates({
   tableView.insertSections([0], with: .top)
 })

그러면 상단에서로드되는 애니메이션이있는 섹션을 0 위치에 삽입합니다. 그러면 cellForRowAt메소드 가 다시 실행 되고 해당 위치에서 새 셀이 확인됩니다. 특정 애니메이션으로이 방법으로 전체 테이블 뷰를 다시로드 할 수 있습니다.

다시 : OP 질문, 대체 테이블보기 상태에 대한 셀을 표시하기 위해 조건부 플래그가 필요했을 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.