답변:
에서 다이나믹 셀rowHeight
jQuery과의 세트는 항상 개별 셀 'rowHeight에 우선합니다.
그러나에 정적 세포,rowHeight
개별 셀에 설정된 UITableView를 재정의 할 수 있습니다.
버그인지 확실하지 않으면 Apple이 의도적으로이 작업을 수행하고있을 수 있습니까?
UITableView
에서 내용을 Dynamic Prototypes
에 Static Cells
, 그했다, 그리고 내 모든 프로젝트는 거의 자신을 살해 ... 폭발.
UITableViewController를 사용하는 경우이 메소드를 구현하십시오.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
행의 기능에서 높이를 선택할 수 있습니다. 예를 들어
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
return 100;
}
else {
return 60;
}
}
이 예에서 첫 번째 행 높이는 100 픽셀이고 다른 행은 60 픽셀입니다.
나는 이것이 당신을 도울 수 있기를 바랍니다.
동적 셀의 rowHeight
경우 UITableView
항상 설정되어 개별 셀의rowHeight
.
이 동작은 버그입니다. 두 곳에서 UI를 관리해야 할 때마다 오류가 발생하기 쉽습니다. 예를 들어 스토리 보드에서 셀 크기를 변경하는 경우 셀 크기도 변경해야 heightForRowAtIndexPath:
합니다. Apple이 버그를 수정할 때까지 현재 가장 좋은 해결 방법은 재정의하는 heightForRowAtIndexPath:
것이지만 스토리 보드의 실제 프로토 타입 셀을 사용하여 마법의 숫자 대신 높이를 결정하십시오 . 예를 들면 다음과 같습니다.
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
/* In this example, there is a different cell for
the top, middle and bottom rows of the tableView.
Each type of cell has a different height.
self.model contains the data for the tableview
*/
static NSString *CellIdentifier;
if (indexPath.row == 0)
CellIdentifier = @"CellTop";
else if (indexPath.row + 1 == [self.model count] )
CellIdentifier = @"CellBottom";
else
CellIdentifier = @"CellMiddle";
UITableViewCell *cell =
[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
return cell.bounds.size.height;
}
그러면 프로토 타입 셀 높이에 대한 변경 사항이 런타임에 자동으로 선택되며 UI를 스토리 보드와 같은 한 곳에서만 관리하면됩니다.
프로토 타입 셀을 사용하는 스토리 보드에서 작동하도록 다양한 답변 / 의견 힌트에 코드를 작성했습니다.
이 코드는 :
Answerbot, Brennan 및 lensovet에게 감사합니다.
- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = nil;
switch (indexPath.section)
{
case 0:
cellIdentifier = @"ArtworkCell";
break;
<... and so on ...>
}
return cellIdentifier;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
static NSMutableDictionary *heightCache;
if (!heightCache)
heightCache = [[NSMutableDictionary alloc] init];
NSNumber *cachedHeight = heightCache[cellIdentifier];
if (cachedHeight)
return cachedHeight.floatValue;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
CGFloat height = cell.bounds.size.height;
heightCache[cellIdentifier] = @(height);
return height;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
<... configure cell as usual...>
실제로 행 높이로 변경 해야하는 두 곳이 있습니다. 먼저 셀을 변경 한 다음 이제 테이블보기를 선택하고 크기 검사기를 확인하십시오.
swift를 사용하는 경우 다음과 같이 사용하십시오. 스토리 보드를 사용하여 행 높이를 선택하지 마십시오. 프로그래밍 방식으로 테이블 행 높이를 다음과 같이 설정하십시오.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 || indexPath.row == 1{
let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
self.tableView.rowHeight = 150
cell.label1.text = "hiiiiii"
cell.label2.text = "Huiiilllllll"
return cell
} else {
let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
self.tableView.rowHeight = 60
cell.label3.text = "llll"
return cell
}
}
cell.sizeToFit(); self.tableView.rowHeight = cell.frame.height
cells
custom을 사용하여 prototype을 사용한 height
다음 . : 을 호출 cellForRowAtIndexPath:
하고 반환 할 수 frame.height
있습니다.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView
cellForRowAtIndexPath:indexPath];
return cell.frame.size.height;
}
나는 최근에 이것과 씨름했다. 내 문제는 위에 게시 된 솔루션이었습니다.heightForRowAtIndexPath:
시뮬레이터에서 iOS 7.1에서 작동 방법을 이지만 iOS 8.1로 간단히 전환하여 결과를 완전히 망쳤습니다.
자체 크기 조정 셀에 대해 더 많이 읽기 시작했습니다 (iOS 8에서 도입, 여기 읽기 ). 사용이 UITableViewAutomaticDimension
iOS 8에서 도움 이 될 것임 이 분명했습니다. 나는 그 기술을 사용해 보았고 사용을 삭제했습니다 heightForRowAtIndexPath:
. 이제 iOS 8에서 완벽하게 작동했습니다. 그러나 iOS 7은 그렇지 않았습니다. 내가 뭘 했어? heightForRowAtIndexPath:
iOS 8이 아니라 iOS 7에 필요 했습니다.
여기에 @JosephH의 답변에서 빌린 내 솔루션 (간결하게 트리밍)이 있습니다.
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 50.;
self.tableView.rowHeight = UITableViewAutomaticDimension;
// ...
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
return UITableViewAutomaticDimension;
} else {
NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
static NSMutableDictionary *heightCache;
if (!heightCache)
heightCache = [[NSMutableDictionary alloc] init];
NSNumber *cachedHeight = heightCache[cellIdentifier];
if (cachedHeight)
return cachedHeight.floatValue;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
CGFloat height = cell.bounds.size.height;
heightCache[cellIdentifier] = @(height);
return height;
}
}
- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
NSString * reuseIdentifier;
switch (indexPath.row) {
case 0:
reuseIdentifier = EventTitleCellIdentifier;
break;
case 2:
reuseIdentifier = EventDateTimeCellIdentifier;
break;
case 4:
reuseIdentifier = EventContactsCellIdentifier;
break;
case 6:
reuseIdentifier = EventLocationCellIdentifier;
break;
case 8:
reuseIdentifier = NotesCellIdentifier;
break;
default:
reuseIdentifier = SeparatorCellIdentifier;
break;
}
return reuseIdentifier;
}
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO (@ "8.0")은 실제로 내가 사용하고있는 어딘가에있는 매크로 정의 세트에서 온 것입니다 (매우 도움이 됨). 그것들은 다음과 같이 정의됩니다 :
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
Swift 4를 사용하여 XCode 9에서 작업 할 때도 동일한 문제가 발생했습니다 .
셀 내부의 UI 요소에 대한 자동 레이아웃 추가 및 사용자 정의 셀 행 높이는 지정된대로 작동합니다.
내가 찾을 수있는 유일한 진정한 해결책은 이것입니다.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
return cell.frame.size.height;
}
이것은 작동하며 스토리 보드에 이미있는 논리를 복제하는 경우 끔찍한 스위치를 가질 수 없습니다. 성능에 대해서는 확실하지 않지만 도착하면 추측합니다.cellForRow:
이미 초기화 된 셀에 하면 빠르다고 생각합니다. 물론 여기에는 부수적 인 피해가있을 수 있지만 여기서는 잘 작동하는 것 같습니다.
나는 또한 이것을 여기에 게시했다 : https://devforums.apple.com/message/772464
편집 : Ortwin Gentz 는 TableView의 모든 셀뿐만 아니라 보이는 셀뿐만 아니라 heightForRowAtIndexPath:
호출 될 것이라고 상기 시켰습니다 . 올바른 스크롤 막대를 표시하려면 iOS에서 전체 높이를 알아야하므로 논리적으로 들립니다. 이는 20 개의 Cell과 같은 작은 TableView에서는 문제가 없지만 1000 Cell TableView에서는 잊어 버리는 것을 의미합니다.
또한 XML의 이전 트릭 : 첫 번째 주석과 같습니다. 올바른 값이 이미있었습니다.
Interface Builder를 통해이 문제에 대한 해결책을 찾지 못했기 때문에 초기 질문에 Interface Builder를 통해 솔루션을 요청했지만 두 개의 동적 셀을 사용하여 Swift 의 문제에 대한 프로그래밍 솔루션을 게시하기로 결정했습니다 . 어쨌든 스택 오버플로 커뮤니티에 도움이 될 수 있다고 생각합니다.
import UIKit
enum SignInUpMenuTableViewControllerCellIdentifier: String {
case BigButtonCell = "BigButtonCell"
case LabelCell = "LabelCell"
}
class SignInUpMenuTableViewController: UITableViewController {
let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]
private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
if indexPath.row == 2 {
return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
} else {
return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
}
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
}
...
}