iOS 8 자동 셀 높이-마지막 행으로 스크롤 할 수 없음
iOS 8의 새로운 자체 크기 조정 셀을 사용하고 있습니다. 시각적으로 잘 작동합니다. 각 셀은 적절한 크기를 갖습니다. 그러나 마지막 행 으로 스크롤 하려고 하면 테이블보기가 올바른 크기를 알지 못하는 것 같습니다. 이것은 버그입니까, 아니면 수정 사항이 있습니까?
문제를 재현하는 방법은 다음과 같습니다.
이 프로젝트 -TableViewCellWithAutoLayoutiOS8 ( 이 SO 답변 에서 참조)을 사용하여 예상대로 자동 크기 조정 셀을 얻었습니다.
그러나 다음과 같이 scrollToRowAtIndexPath 함수를 호출하는 경우 :
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)
나는 마지막 줄에 도착하지 않습니다 .
다음과 같이 낮은 수준의 기능을 사용하려고해도 :
tableView.setContentOffset(CGPointMake(0, tableView.contentSize.height - tableView.frame.size.height), animated: true)
결과는 예상과 다르며 끝까지 도달하지 않습니다. 여러 번 클릭하거나 잠시 기다리면 결국 올바른 위치로 이동합니다. tableView.contentSize.height가 올바르게 설정되지 않은 것 같습니다. 그래서 iOS는 마지막 셀이 어디에 있는지 "모릅니다".
도움을 주시면 감사하겠습니다.
감사
업데이트 : 2015 년 6 월 24 일
Apple은 iOS 9.0 SDK에서 이러한 버그의 대부분을 해결했습니다. 애니메이션없이 테이블보기의 상단 및 하단으로 reloadData
스크롤하고 테이블보기 중간에서 스크롤 하는 동안 호출 하는 등 모든 문제가 iOS 9 베타 2부터 수정되었습니다 .
아직 수정되지 않은 나머지 문제는 다음과 같습니다.
- 큰 예상 행 높이를 사용하는 경우 애니메이션이있는 마지막 행으로 스크롤하면 테이블보기 셀이 사라집니다.
- 작은 예상 행 높이를 사용하는 경우 애니메이션이있는 마지막 행으로 스크롤하면 테이블보기가 너무 일찍 스크롤을 완료하여 일부 셀이 가시 영역 아래 (그리고 마지막 행은 여전히 화면을 벗어남)에 남게됩니다.
애니메이션 스크롤과 관련된 이러한 문제에 대한 새로운 버그 보고서 (rdar : // 21539211)가 제출되었습니다.
원래 답변
이것은 테이블보기 행 높이 추정 기능이있는 Apple 버그이며,이 기능이 iOS 7에서 처음 도입 된 이후 존재했습니다. 저는이 문제에 대해 Apple UIKit 엔지니어 및 개발자 전도자와 직접 작업했습니다. 버그이지만 신뢰할 수있는 해결 방법이 없으며 (행 높이 추정을 비활성화하는 것보다 부족함) 특별히 수정하는 데 관심이없는 것 같습니다.
버그는 reloadData
부분적으로 또는 완전히 아래로 스크롤 한 상태에서 호출하면 테이블 뷰 셀이 사라지는 것과 같은 다른 방식으로 나타납니다 (예 : contentOffset.y
0보다 훨씬 큼).
분명히 iOS 8 자체 크기 조정 셀에서는 행 높이 추정이 매우 중요하므로 Apple은이 문제를 최대한 빨리 해결해야합니다.
이 문제는 2013 년 10 월 21 일에 Radar # 15283329로 다시 제출했습니다. Apple이 수정에 우선 순위를 부여 할 수 있도록 중복 버그 보고서를 제출하십시오.
이 간단한 샘플 프로젝트 를 첨부 하여 문제를 보여줄 수 있습니다 . Apple의 자체 샘플 코드를 직접 기반으로합니다.
이것은 매우 성가신 버그 였지만 이유를 완전히 설명 할 수는 없지만 영구적 인 해결책을 찾은 것 같습니다.
약간의 (눈에 띄지 않는) 지연 후에 함수를 호출합니다.
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)
})
이것이 당신에게도 효과가 있는지 말해주십시오.
확실히 Apple의 버그입니다. 나는 또한이 문제가 있습니다. "scrollToRowAtIndexPath"메서드를 두 번 호출하여이 문제를 해결했습니다. 예제 코드는 다음과 같습니다.
if array.count > 0 {
let indexPath: NSIndexPath = NSIndexPath(forRow: array.count - 1, inSection: 0)
self.tblView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
self.tblView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
})
}
Apple이 우리를 괴롭히는 많은 버그를 수정하기로 결정할 때까지 도움이 될 수있는 임시 해결 방법을 찾았습니다.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *text = [self findTextForIndexPath:indexPath];
UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:13];
CGRect estimatedHeight = [text boundingRectWithSize:CGSizeMake(215, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: font}
context:nil];
return TOP_PADDING + CGRectGetHeight(estimatedHeight) + BOTTOM_PADDING;
}
이것은 완벽하지는 않지만 나를 위해 일했습니다. 이제 다음과 같이 전화 할 수 있습니다.
- (void)scrollToLastestSeenMessageAnimated:(BOOL)animated
{
NSInteger count = [self tableView:self.tableView numberOfRowsInSection:0];
if (count > 0) {
NSInteger lastPos = MAX(0, count-1);
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:lastPos inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
}
}
켜고 viewDidLayoutSubviews
바닥에서 올바른 위치 (또는 매우 가까운 예상 위치)를 찾습니다.
도움이 되었기를 바랍니다.
제 경우에는 예상 셀 높이를 프로그램에 제안하지 않음으로써 임시 해결 방법을 찾았습니다. 내 코드에서 다음 방법을 주석으로 처리했습니다.
- (CGFloat) tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
그러나 셀이 서로 비교하여 많이 다를 경우 사용자가 스크롤 할 때 사용자 경험에 영향을 미칠 수 있습니다. 제 경우에는 지금까지 눈에 띄는 차이가 없습니다.
도움이 되었기를 바랍니다.
내 해결책은 스토리 보드의 크기를 추정치로 사용하는 것이 었습니다.
그래서이 대신 :
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
나는 다음과 같이했다.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
MyMessageType messageType = [self messageTypeForRowAtIndexPath:indexPath];
switch (messageType) {
case MyMessageTypeText:
return 45;
break;
case MyMessageTypeMaybeWithSomeMediaOrSomethingBiggerThanJustText:
return 96;
break;
default:
break;
}
}
채팅 테이블보기를 작성 중이므로 많은 셀, 특히 해당 텍스트 유형이 IB에있는 것보다 클 가능성이 높습니다. 특히 채팅 메시지가 매우 긴 경우 더욱 그렇습니다. 이것은 꽤 좋은 것 같습니다 ... 음 ... 추정하고 아래로 스크롤하면 꽤 가까워집니다. 스크롤링이 길어질수록 약간 더 나빠지는 것 같지만 예상 할 수 있습니다.
viewDidAppear가 문제를 해결할 수있는 후에 tableview reloadData를 호출하기 만하면됩니다.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView reloadData];
}
smileyborg의 대답 으로 iOS 8.x의 버그 이지만 지원하는 모든 플랫폼에서 수정해야합니다 ...
iOS9 이전의 문제를 해결하려면 아래 코드에서 dispatch_async 또는 dispatch_after없이 트릭을 수행하십시오. iOS 8.4 시뮬레이터에서 테스트되었습니다.
업데이트 : 스크롤되는 UIPageViewController에 의해 뷰 컨트롤러가 표시되면 layoutIfNeeded 호출 (전용)이 작동하지 않습니다. 따라서 layoutSubviews (또는 setNeedsLayout + layoutIfNeeded)를 대신 사용하십시오.
// For iOS 8 bug workaround.
// See https://stackoverflow.com/a/33515872/1474113
- (void)scrollToBottomForPreiOS9
{
CGFloat originalY, scrolledY;
do {
// Lay out visible cells immediately for current contentOffset.
// NOTE: layoutIfNeeded does not work when hosting UIPageViewController is dragged.
[self.tableView layoutSubviews];
originalY = self.tableView.contentOffset.y;
[self scrollToBottom]; // Call -scrollToRowAtIndexPath as usual.
scrolledY = self.tableView.contentOffset.y;
} while (scrolledY > originalY);
}
셀 높이가 다른 채팅 tableView를 만들 때 동일한 문제가 발생했습니다. viewDidAppear () 수명주기 메서드에서 아래 코드를 호출합니다.
// First figure out how many sections there are
let lastSectionIndex = self.tableView.numberOfSections - 1
// Then grab the number of rows in the last section
let lastRowIndex = self.tableView.numberOfRowsInSection(lastSectionIndex) - 1
// Now just construct the index path
let pathToLastRow = NSIndexPath(forRow: lastRowIndex, inSection: lastSectionIndex)
// Make the last row visible
self.tableView.scrollToRowAtIndexPath(pathToLastRow, atScrollPosition: UITableViewScrollPosition.None, animated: true)
그것이 당신에게도 효과가 있는지 알려주십시오.
스토리 보드 창에서 빈 영역을 클릭하여 모든보기를 선택 취소 한 다음 테이블보기가있는보기를 클릭 한 다음 Resolve Auto Layout Issue
아이콘 을 클릭하고Reset to Suggested Constraints
이 간단한 코드를 사용하여 아래로 스크롤하십시오.
var rows:NSInteger=self.tableName.numberOfRowsInSection(0)
if(rows > 0)
{
let indexPath = NSIndexPath(forRow: rows-1, inSection: 0)
tableName.scrollToRowAtIndexPath(indexPath , atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
}
}
참조 URL : https://stackoverflow.com/questions/25686490/ios-8-auto-cell-height-cant-scroll-to-last-row
'Nice programing' 카테고리의 다른 글
다른 포트 뒤에있는 단일 Tomcat 인스턴스에서 다른 앱을 실행하는 방법은 무엇입니까? (0) | 2020.12.25 |
---|---|
날짜 범위가있는 적절한 REST 형식 URL (0) | 2020.12.25 |
PHP에서 fopen 모드 "r +"와 "rw +"의 차이점은 무엇입니까? (0) | 2020.12.25 |
C ++ 17에 std :: construct_at가없는 이유는 무엇입니까? (0) | 2020.12.25 |
Tomcat 6을 삽입하는 방법? (0) | 2020.12.25 |