2013-09-07 2 views
2

레이블이 상대적으로 정적 인 두 개의 셀과 레이블 및 분할 된 컨트롤이 포함 된 일련의 사용자 지정 셀이있는 TableView를 표시하는 응용 프로그램이 있습니다. 이 셀은 레이블의 텍스트 양에 따라 높이가 달라야합니다.TableView 동적 행 높이가 호출되지 않음

cellForRowAtIndexPath에서 필요한 셀 높이를 계산하고 값을 배열에 저장 한 다음 heightForRowAtIndexPath에서 해당 배열의 값을 사용하고 있습니다. 그러나 heightForRowAtIndexPath가 먼저 호출되기 때문에 모든 행 높이가 0/nil입니다.

셀을 구성하기 전에 셀 높이를 알아야 할 때 셀의 특정 내용을 기반으로 행 높이를 어떻게 지정할 수 있습니까? cellForRowAtIndexPath에서

발췌문 :

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSInteger currentIndex = indexPath.item; 
    if (indexPath.item == 0){ 
     static NSString *CellIdentifier = @"MeasurementCell"; 
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
     [self.cellHeightList insertObject:[NSNumber numberWithInt:44] atIndex:currentIndex]; 
     return cell; 
    } else if (indexPath.item == 1){ 
     if (self.dataController.isScoreAvailable){ 
      static NSString *CellIdentifier = @"ScoreCell"; 
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
      [self.cellHeightList insertObject:[NSNumber numberWithInt:46] atIndex:currentIndex]; 
      return cell; 
     } else { 
      static NSString *CellIdentifier = @"ScoreCell"; 
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
      cell.accessoryType = UITableViewCellAccessoryNone; 
      [self.cellHeightList insertObject:[NSNumber numberWithInt:0] atIndex:currentIndex]; 
      return cell; 
     } 
    } else if (indexPath.item > 1){ 
     NSInteger labelWidth = [UIScreen mainScreen].applicationFrame.size.width - 140; //80 for segment + 3*20 for margins & spacing 
     CGSize maxSize = CGSizeMake(labelWidth, MAXFLOAT); 
     CGSize labelSize; 

     static NSString *CellIdentifier = @"QuestionCell"; 
     InterviewQuestionCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
     InterviewQuestion *questionAtIndex = [self.dataController objectInListAtIndex:(indexPath.item-2)]; 
     cell.questionLabel.text = questionAtIndex.questionText; 
     labelSize = [cell.questionLabel.text sizeWithFont:[UIFont systemFontOfSize:12.0] constrainedToSize:maxSize lineBreakMode:NSLineBreakByWordWrapping]; 
     CGRect labelFrame = CGRectMake(0, 0, labelWidth, labelSize.height); 
     cell.questionLabel.frame = labelFrame; 
     cell.questionLabel.numberOfLines = 0; 
     cell.answerControl.selectedSegmentIndex = questionAtIndex.answer; 
     cell.answerControl.tag = indexPath.item; 
     [self.cellHeightList insertObject:[NSNumber numberWithInt:labelSize.height] atIndex:currentIndex]; 
     return cell; 
    } 
    return nil; 
} 

코드 heightForRowAtIndexPath에서는 :

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSInteger currentIndex = indexPath.item; 
    return [[self.cellHeightList objectAtIndex:currentIndex] integerValue]; 
} 

당신을 감사합니다!

답변

2

먼저 indexPath에서 'item'을 사용하지 말고 'row'를 사용하십시오. 항목은 UITableView가 아니라 UICollectionView에 의해 사용됩니다. 둘째, 셀이 없어도 셀 크기를 계산해야합니다. 귀하의 tableView 특정 너비, 그래서 그것을 기반으로 필요한 높이를 계산할 수 있습니다. 이 계산을 heightForRowAtIndexPath에 두십시오 (집중적 인 경우 캐시).

구체적하지 cellForRowAtIndexPath이 아니라 heightForRowAtIndexPath에 다음 코드를 넣습니다 :

또한
NSInteger labelWidth = [UIScreen mainScreen].applicationFrame.size.width - 140; 
CGSize maxSize = CGSizeMake(labelWidth, MAXFLOAT); 
CGSize labelSize; 

는 대신 UIScreen를 사용, 단순히있는 tableView의 폭을 사용, 그것은 당신의 코드가 덜 밀접하게 결합한다.

+0

오히려 '항목'보다, '행'에 대한 팁을 주셔서 감사합니다 . 나는 그것이 조금 더 깨끗하다고 ​​생각한다. 늘어나는 코드를 heightForRowAtIndexPath에 추가하는 한, 인터뷰 질문에서 텍스트를 가져와야합니다. 두 곳에서 InterviewQuestion 객체의 텍스트를 가져 오기 위해 호출하는 것이 더 깔끔한가요? 아니면 한 번 당겨서이 ViewController의 속성에 저장해야합니까? – liv2code

+0

권장되는 방법은 해당 textItems를 속성 (NSArray)에 저장하는 것입니다. 이렇게하면 추가 작업없이 두 위치에서 항목에 액세스 할 수 있습니다. 또한 해당 배열에서 항목이 변경되면 -reloadCellAtIndexPath :를 호출하면 셀이 다시로드됩니다.(또는 논리가 괜찮은지 확인하기 위해 개발하는 동안 큰 추악한 망치 : -reloadData를 사용할 수 있습니다.) – Joride

0

Joride의 답변을 좋은 출발점으로 사용하고 레이블 높이 기능을 별도의 기능으로 가져 왔습니다. 나는 그 하나 더 노치를 추상화하고 그 함수의 레이블에 대한 실제 CGSize를 반환하여 heightForRowAtIndexPath와 cellForRowAtIndexPath에서 깨끗하게 호출 할 수 있다고 생각합니다. 아래에 업데이트 된 코드를 포함 시켰습니다.

cellForRowAtIndexPath :

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    { 
     NSInteger currentIndex = indexPath.row; 
     if (currentIndex == 0){ 
      static NSString *CellIdentifier = @"MeasurementCell"; 
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
      [[cell textLabel] setText:@"Eating"]; 
      [self.cellHeightList insertObject:[NSNumber numberWithInt:44] atIndex:currentIndex]; 
      return cell; 
     } else if (currentIndex == 1){ 
      if (self.dataController.isScoreAvailable){ 
       static NSString *CellIdentifier = @"ScoreCell"; 
       UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
       [[cell textLabel] setText:@"Score"]; 
       [[cell detailTextLabel] setText:@"Score short description"]; 
       [self.cellHeightList insertObject:[NSNumber numberWithInt:46] atIndex:currentIndex]; 
       return cell; 
      } else { 
       static NSString *CellIdentifier = @"ScoreCell"; 
       UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
       [[cell textLabel] setText:@""]; 
       [[cell detailTextLabel] setText:@""]; 
       cell.accessoryType = UITableViewCellAccessoryNone; 
       [self.cellHeightList insertObject:[NSNumber numberWithInt:0] atIndex:currentIndex]; 
       return cell; 
      } 
     } else if (currentIndex > 1){ 
      NSInteger labelWidth = [UIScreen mainScreen].applicationFrame.size.width - 140; 
      CGSize maxSize = CGSizeMake(labelWidth, MAXFLOAT); 

      static NSString *CellIdentifier = @"QuestionCell"; 
      InterviewQuestionCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
      InterviewQuestion *questionAtIndex = [self.dataController objectInListAtIndex:(currentIndex-2)]; 
      cell.questionLabel.text = questionAtIndex.questionText; 
      CGSize labelSize = [cell.questionLabel.text sizeWithFont:[UIFont systemFontOfSize:12.0] constrainedToSize:maxSize lineBreakMode:NSLineBreakByWordWrapping]; 
      CGRect labelFrame = CGRectMake(0, 0, labelWidth, labelSize.height); 
      cell.questionLabel.frame = labelFrame; 
      cell.questionLabel.numberOfLines = 0; 
      cell.answerControl.selectedSegmentIndex = questionAtIndex.answer; 
      cell.answerControl.tag = indexPath.item; 
      [self.cellHeightList insertObject:[NSNumber numberWithInt:labelSize.height] atIndex:currentIndex]; 
      return cell; 
     } 
     return nil; 
    } 

heightForRowAtIndexPath :

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSInteger currentIndex = indexPath.row; 
    if (currentIndex == 0){ 
     return 44; 
    } else if (currentIndex == 1){ 
     if (self.dataController.isScoreAvailable){ 
      return 46; 
     } else { 
      return 0; 
     } 
    } else if (currentIndex > 1){ 
     return [self getRowHeightForRow:currentIndex]; 
    } 
    return 0; 
} 

새로운 getRowHeightForRow 기능 :

- (NSInteger)getRowHeightForRow:(NSInteger)currentRow{ 
    NSInteger labelWidth = [UIScreen mainScreen].applicationFrame.size.width - 140; //80 for segment + 3*20 for margins & spacing 
    CGSize maxSize = CGSizeMake(labelWidth, MAXFLOAT); 
    InterviewQuestion *questionAtIndex = [self.dataController objectInListAtIndex:(currentRow-2)]; 
    NSString *questionText = questionAtIndex.questionText; 
    CGSize labelSize = [questionText sizeWithFont:[UIFont systemFontOfSize:12.0] constrainedToSize:maxSize lineBreakMode:NSLineBreakByWordWrapping]; 
    return labelSize.height; 

} 
+0

좋아 보인다. 코드를 더 잘 읽을 수 있도록 NSNumbers에 현대적인 Objective-C를 사용하는 것이 좋습니다. 대신. "[NSNumber numberWithInt : 46]"을 사용하면 "@ (46)"을 사용할 수 있습니다 (따옴표 제외). 컴파일러는이 코드를 사용하여 NSNumber를 만들고 코드는 기본적으로 동일하지만 가독성이 뛰어납니다. – Joride

1
You can use autolayout and set the height based on the content in the content view 
you need to set 

//swift 

    override func viewDidLoad() 
     { 
      self.tableView.estimatedRowHeight = 180 
     } 

    // return UITableViewAutomaticDimension 
     override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 
     { 
      return UITableViewAutomaticDimension 
     } 



//Objective C 

     - (void)viewDidLoad 
     { 
      [super viewDidLoad]; 
      self.tableview.estimatedRowHeight = 180.0 ; 

     } 

     -(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
    { 
     //constraint for autolayout for ios8+ 
     return UITableViewAutomaticDimension; 
    } 
+0

사실 'heightForRowAtIndexPath'를 호출 할 필요가 없습니다. viewDidLoad (또는 viewWillAppear)에서 사용할 수 있습니다 :'tableView.rowHeight = UITableViewAutomaticDimension' – TheoK

관련 문제