2014-09-20 3 views
54

내가 만들고있는이 iOS 8 응용 프로그램에서는 tableview가 있으며 자체 크기 조정이 필요합니다. 자동 레이아웃을 사용하여 구현하고 작동합니다. 거의. 여기 보이는 방법이 있습니다.자체 크기 조정 UITableViewCell 안에 여러 UILabels

enter image description here

는 셀 내부에 3 개 라벨이 있습니다. lorem ipsum 텍스트가있는 주 레이블. 자막은 숫자 문자열을 가지고 있습니다 (두 개의 별도 레이블입니다. 동일한 색상을 사용하기 때문에 혼동 스러울 수 있습니다.) 그런 다음 작은 검은 색 텍스트가있는 세 번째 레이블.

첫 번째 레이블 자체가 문제없이 올바르게 크기가 조정되고 그에 따라 두 번째 레이블이 위아래로 이동합니다. 그러나 문제는 세 번째 작은 레이블입니다. 보시다시피, 모든 텍스트에 맞게 크기가 조정되지 않습니다.

이제 이상한 일이 발생했습니다. 나는 그것을 가로로 돌리고 여기있다.

enter image description here

공간 라벨이에 가정 전체 텍스트를 표시하고이 있기 때문에. 벌금. 그런 다음 초상화로 되돌립니다.

enter image description here

지금 작은 레이블 모든 텍스트에 맞게 자체적으로 크기가 조정했지만 그것은 세포의 경계를 오버 플로우. 나는 세포를 더 크게 만들려고했으나 효과가 없었다. 이것은 셀을 셀 사이징하는 것이므로 올바른 방법이라고 생각하지 않습니다.

내 자동 레이아웃 제약 조건에서도 오류 또는 경고가 표시되지 않습니다.

enter image description here

나는 viewDidLoad() 방법 코드의 두 라인을 설정했습니다.

tableView.estimatedRowHeight = 100 
tableView.rowHeight = UITableViewAutomaticDimension 

아무도 내가 여기서 잘못하고있는 것일 수 있습니까?

그냥 이미지를보고 대답하기가 어렵고 위의 코드 조각 옆에 게시 할 코드가 더 이상 없기 때문에 문제가있는 실행 가능한 Xcode 프로젝트를 업로드했습니다 here. (사용자 정의 셀이 2 개 있습니다. 기본적으로 두 번째 셀에서 높이가 증가한 동일한 셀이 있습니다.)

자동 레이아웃 제약으로 인해 작업 해본 결과이 작업을 수행하지 못했습니다. 어떤 도움을 주시면 감사하겠습니다.

감사합니다.


UPDATE

tutorial의 도움으로

나는 몇 가지 유용한 포인터를 발견했다. 그것에 따르면 각 하위 뷰에는 모든면을 고정하는 제약 조건이 있어야하며 자동 레이아웃이 셀 높이를 계산하는 데 도움이되는 위에서 아래로 오는 제약 조건이 있어야합니다. 내 원래 게시물에서 각 레이블 사이에 세로 간격이있어서 자동 레이아웃이 적절한 높이를 계산할 수없는 이유라고 생각합니다.

그래서 몇 가지 사항을 변경했습니다.

  • 나는 레이블 사이의 수직 간격을 0으로 줄이고 상단 및 중간 레이블과 중간 및 하단 레이블 사이의 수직 공간 제약 조건을 설정했습니다.
  • 맨 위 레이블에 선행, 맨 위, 후행 제약 조건을 추가했습니다.
  • 중간 레이블 앞과 뒤.
  • 아래쪽으로 이어지는 선행, 아래쪽 레이블.

이제 또 다른 이상한 부분이 있습니다. 처음 실행할 때 밑줄 자르기 문제가 여전히 있습니다. 나는 풍경에 장치를 회전하여 세로로 다시 켜면

enter image description here

그러나, 모든 모든 세포는 모두 라벨에 맞게 적절하게 조정됩니다!

enter image description here

아직도이 비록 처음에는 발생하지 않는 이유를 알아낼 수 없습니다. 업데이트 된 Xcode 프로젝트는 here입니다.

+3

이 표는 너무 어려운 전에 라벨에 텍스트의 정확한 높이를 추정하기 위해 찾는 요청 보기가 나타나지만 모두 똑같이 잘하고 있습니다. 나는 당신이 viewDidAppear로 tableView.estimatedRowHeight = 100을 이동했다면 발견 한 문제를 해결했다. – sketchyTech

+1

... 아니면 오히려 테이블이 예상되는 높이를 사용하여 첫 번째 로딩시 정확한 계산을하지 못하는 것으로 보인다. 탁자. 그러나 estimatedRowHeight가 설명한대로 이동하면 현재보고있는 문제가 해결됩니다. 모두 제거하면 rotate에서 다시 그리기 문제가 발생합니다. – sketchyTech

+0

@GoodbyStackOverflow 제안대로했는데 문제가 있습니다. [이것이 실행될 때의 모습입니다] (http://i.imgur.com/1CNGVgR.png) 및 [아래로 스크롤 할 때] (http://i.imgur.com/lH7hasO.png).나는 두 번째 예제에도 똑같이 적용했으며 [결과] (http://i.imgur.com/AWg9Yib.png)입니다. 처음 3 개의 셀에서 잘 보이지만 마지막 셀에서 엉망이되었습니다. – Isuru

답변

75

문제는 여러 줄 레이블 'preferredMaxLayoutWidth 속성입니다. 이것은 단어를 감쌀 때 라벨을 알려주는 속성입니다. 각 레이블의 intrinsicContentSize이 올바른 높이를 가지려면 올바르게 설정해야하며 궁극적으로 자동 레이아웃이 셀 높이를 결정하는 데 사용됩니다.

Xcode 6 Interface Builder에서이 속성을 으로 설정하는 새로운 옵션을 도입했습니다. 자동. 불행히도, 펜촉이나 스토리 보드에서 셀을로드 할 때 이것이 올바르게/자동으로 설정되지 않은 심각한 버그가 있습니다 (Xcode 6.2/iOS 8.2).

이 버그를 해결하려면 테이블보기에 표시된 후 preferredMaxLayoutWidth을 레이블의 최종 너비와 정확히 동일하게 설정해야합니다. 효과적으로, 우리는 tableView:cellForRowAtIndexPath:에서 셀을 반환하기 전에 다음을 수행 할 : 단지 코드의이 3 선이 tableView:cellForRowAtIndexPath:에서 실행할 때, 우리는을 사용하고 있기 때문에 작동하지 않습니다 만,이 코드를 추가

cell.nameLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.nameLabel.frame) 
cell.idLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.idLabel.frame) 
cell.actionsLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.actionsLabel.frame) 

이유 너비가 preferredMaxLayoutWidth 인 각 레이블의 너비 - 그러나이 시점에서 레이블의 너비를 확인하면 레이블 너비는 셀이 표시되고 하위보기가 놓여지는 시점과 완전히 다릅니다. 아웃.

레이블 너비가 최종 너비를 반영하도록이 시점에서 어떻게 정확합니까? 모두 함께 모으는 코드는 다음과 같습니다.

// Inside of tableView:cellForRowAtIndexPath:, after dequeueing the cell 

cell.bounds = CGRect(x: 0, y: 0, width: CGRectGetWidth(tableView.bounds), height: 99999) 
cell.contentView.bounds = cell.bounds 
cell.layoutIfNeeded() 

cell.nameLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.nameLabel.frame) 
cell.idLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.idLabel.frame) 
cell.actionsLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.actionsLabel.frame) 

그래, 여기서 뭐하는거야? 글쎄, 3 줄의 새로운 코드가 추가되었음을 알 수 있습니다. 먼저 테이블 뷰의 실제 너비와 일치하도록이 테이블 뷰 셀의 너비를 설정해야합니다 (테이블 뷰가 이미 배치되어 있고 최종 너비가 있어야 함을 전제로합니다). 우리는 테이블 뷰가 결국 이렇게 할 것이기 때문에 셀 폭을 일찍 수정하는 것이 효과적입니다.

또한 높이에 99999을 사용하고 있습니다. 그것에 대해 무엇입니까? 이는 세부 사항 here에서 논의 된 문제에 대한 간단한 해결 방법입니다. 제약 조건에서 셀의 contentView의 현재 높이보다 더 많은 수직 공간이 필요한 경우 실제 문제를 나타내지 않는 제약 조건 예외가 발생합니다. 셀의 높이나 하위 뷰 중 하나의 높이는 실제로는 중요하지 않습니다. 왜냐하면 각 레이블의 최종 너비 만 알아두기 때문입니다.

다음으로 우리는 contentView의 경계를 셀의 경계와 동일하게 설정하여 셀의 contentView가 방금 셀 자체에 할당 한 것과 동일한 크기를 가지도록합니다. 이는 작성한 모든 자동 레이아웃 제한 조건이 contentView와 관련되어 있기 때문에 필요합니다. 따라서 contentView가 올바르게 해결되도록 올바른 크기 여야합니다. 셀의 크기를 수동으로 설정하면 이 아닌의 contentView가 자동으로 크기가 조정됩니다.

마지막으로 강제 레이아웃을 셀에 적용하면 자동 레이아웃 엔진이 제약 조건을 풀고 모든 하위 뷰의 프레임을 업데이트합니다. 셀 & contentView는 이제 테이블보기에서 런타임에 동일한 너비를 갖기 때문에 레이블 폭도 정확합니다. 즉, 각 레이블에 설정된 preferredMaxLayoutWidth이 정확하고 적절한 시간에 레이블이 줄 바꿈됩니다 물론 셀이 테이블 뷰에서 사용될 때 레이블의 높이가 올바르게 설정됩니다!

이것은 우리가 지금 해결해야하는 UIKit의 Apple 버그입니다. 따라서 Apple에 file bug reports으로 수정하여 우선 순위를 지정하십시오!).

최종주의 사항 : 오른쪽에 섹션 색인이있는 경우와 같이 테이블보기 셀의 contentView 너비가 표보기의 전체 너비를 확장하지 않으면이 해결 방법은 문제가됩니다. 이 경우 셀의 폭을 설정할 때 수동으로이 점을 고려해야하는지 확인해야합니다 -이 값을 하드 코딩해야 할 수도 있습니다, 같은 :

let cellWidth = CGRectGetWidth(tableView.bounds) - kTableViewSectionIndexWidth 
cell.bounds = CGRect(x: 0, y: 0, width: cellWidth, height: 99999) 
+0

@Isuru 셀에 레이아웃 패스를 강제 한 후에 얻을 수있는 만족할만한 제약 조건 예외는 실제 문제가 아니며 쉽게 해결할 수 있습니다. 이 문제에 대한 자세한 내용은 [이 스레드] (https://github.com/smileyborg/TableViewCellWithAutoLayout/issues/16)를 참조하십시오. – smileyborg

+0

감사합니다. 내 라벨을 올바르게 크기를 조정할 수있는 모든 것을 시도하면서 2 일을 보냈습니다. 이상한 일은 크기를 조정 한 것이지만 다른 셀 디자인은 크기를 조정하지 못했습니다. 제약 조건이나 다른 설정에서 차이점을 찾을 수 없었습니다. 그러나 솔루션은 훌륭하게 작동했습니다. UILabel 서브 클래스를 만들고 setBounds 내에 preferredMaxLayoutWidth 설정을 넣어 테이블 뷰 컨트롤러의 UILabels에 대한 하드 참조를 피했습니다. –

+2

당신은 내 영웅입니다! – pr1001

4

여기에는 두 가지 문제가 있습니다.

1/지금, 비주얼 형식 언어를 사용하여 셀의 수직 제약 조건은 다음과 같이 번역 할 수 있습니다

Cell: "V:|-(10)-[nameLabel]-(8)-[pnrLabel]-(2)-[actionsLabel]" 

그 두 : 다음

Cell: "V:|-(10)-[nameLabel]-(67)-|" 

, 당신은 제약 조건의 두 번째 그룹을 설정 제약 그룹은 잘 섞여서는 안되며 두 번째 문제로 인해 모호성이 드러납니다.

2/이유를 들어, actionsLabel은 앱을 시작할 때 한 줄로 제한됩니다. 그런 다음 가로 모드로 기기를 회전하면 actionsLabel은 두 줄 이상으로 표시되도록 허용합니다. 그런 다음 장치를 세로 모드로 다시 돌리면 actionsLabel은 두 줄 이상을 계속 표시합니다. 그러나 actionsLabel은 실제로 셀 높이 제약 조건의 일부가 아니므로 셀 경계를 오버랩합니다.

모든 문제를 해결하려면 먼저 xib 파일을 처음부터 다시 작성하는 것이 좋습니다. 이것은 actionsLabel 이상한 동작 (장치를 회전시킬 때만 2 줄 이상)을 치료할 것입니다.

그런 다음,이 같은 제약 조건을 정의해야합니다 : 물론

Cell: "V:|-(10)-[nameLabel(>=21)]-(8)-[pnrLabel(>=21)]-(2)-[actionsLabel(>=21)]-(10)-|" 

, 당신은 (>=21) 것보다 레이블 다른 최소 높이 제약 조건을 정의 할 수 있습니다. 같은 방법으로 하단 여백을 -(10)-이 아닌 다른 값으로 설정할 수 있습니다.

부록

은 귀하의 질문에 대답하기 위해, 나는 내 .xib 파일에서 이전 제약 패턴으로 간단한 프로젝트를 만들었습니다. 다음 그림은 자신 만의 제약 조건을 구축하는 데 도움이 될 수 있습니다.여기

enter image description here

+0

위대하고 간결한 대답입니다. – memmons

+0

자세한 답변 해 주셔서 감사합니다. 나는 그럭저럭 일할 수 있었다. 그러나 사소한 문제가있다. 이 레이블의 너비는 고정되어 있으므로 화면을 가로로 돌릴 때 여분의 공간을 채우기 위해 조정되지 않습니다. 이 문제를 해결할 수있는 방법이 있습니까? 이러한 레이블에서 Superview에 후미 공백을 추가하면 작동하지 않는 것 같습니다. – Isuru

+0

테스트 목적으로 테스트 프로젝트의 각 라벨에 대해 폭 제약을 설정했습니다. 앱에서 너비 제약 조건을 설정하지 말고 각 라벨의 후행 공백을 슈퍼 뷰 여백 제한 조건으로 설정하십시오. 동시에 각 레이블에 대한 너비 제약 조건과 후행 공백을 슈퍼 뷰 여백 제약 조건으로 설정하지 마십시오. 둘 중 하나를 선택해야합니다. –

48

을 저도 같은 문제를 만났다 당신과 나는 그것을 해결하기위한 간단한 해결책을 찾았습니다.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    // dequeue cell... 

    // do autolayout staffs...or if the autolayout rule has been set in xib, do nothing 

    [cell layoutIfNeeded]; 

    return cell; 
} 

자동 크기 조정이 잘 작동합니다. 내 코드에서는 두 개의 레이블을 세로로 놓았고, 둘 다 동적 높이입니다. 셀의 높이는 두 레이블을 포함하도록 올바르게 설정됩니다.

+2

이것은 가장 좋은 대답입니다. preferredMaxLayoutWidth 설정에 대한 대답은 여전히 ​​내 경험에 문제가 있습니다. –

+0

쳇, 나는 대답을 온통 들여다 보았다. 이 모든 복잡한 복잡하지 않은 솔루션. 여기, 한 줄의 코드. done ... – zillaofthegods

+2

smileyborg의 해결책이있는 동안 불행하게도 나는 이것이 나를 위해 작동하지 않는다는 것을 발견했습니다. iOS8 기준 – pr1001

6

다른 사람들이 제안한대로 제약 조건에 오류가 없다고 가정하면이 문제는 UITableViewCellAccessory와 함께 여러 줄을 허용하는 UILabel을 사용하는 것으로 나타납니다. iOS가 셀을 레이아웃하고 높이를 결정할 때,이 액세서리로 인해 발생하는 너비의 오프셋 변화를 고려하지 않으며 예상치 못한 부분에서 잘라냅니다.

당신이 UILabel의 콘텐츠 뷰의 전체 폭을 확장하려는 가정, 나는 모든 글꼴이를 해결

-(void)fixWidth:(UILabel *)label forCell:(UITableViewCell *)cell { 
    float offset = 0; 
    switch ([cell accessoryType]) { 
     case UITableViewCellAccessoryCheckmark: 
      offset = 39.0; 
      break; 
     case UITableViewCellAccessoryDetailButton: 
      offset = 47.0; 
      break; 
     case UITableViewCellAccessoryDetailDisclosureButton: 
      offset = 67.0; 
      break; 
     case UITableViewCellAccessoryDisclosureIndicator: 
      offset = 33.0; 
      break; 
     case UITableViewCellAccessoryNone: 
      offset = 0; 
      break; 
    } 
    [label setPreferredMaxLayoutWidth:CGRectGetWidth([[self tableView]frame]) - offset - 8]; 
} 

는 단순히 cellForRowAtIndexPath에 넣고 크기하는 방법을 썼다

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    #Setup the cell 
    ... 
    // Fix layout with accessory view 
    [self fixWidth:[cell label] forCell:cell]; 
    return cell; 
} 

너비를 적절하게 조정 한 다음 적절한 높이를 다시 계산하려면 여러 줄로 구성된 모든 레이블에 대해이 작업을 수행하십시오. 이것은 동적 글꼴 크기에서도 작동합니다.

smileyborg가 언급 한 것처럼, contentView의 전체 너비를 사용하지 않았다면 제약 조건을 참조하고 너비에서도 빼낼 수 있습니다.

편집 : 이전에 셀에 'layoutIfNeeded'를 실행 중이었지만 성능 문제가 발생하여 어쨌든 필요하지 않은 것 같습니다. 그것을 제거하는 것은 나를 위해 어떤 문제도 일으키지 않았다.

1

나는 매우 쉽고 우아하게 보이는 "fogisland"솔루션을 시도했지만 작동하지 않았습니다. 다행히도 한 줄의 추가 라인이 다른 방향으로 작동한다는 것을 알게되었습니다. 그냥뿐만 아니라 새로운 레이아웃 (layoutIfNeeded을) 제안 시스템에게, 당신은 명시 적으로 (setNeedLayout)

cell.setNeedsLayout() 
    cell.layoutIfNeeded() 
    return cell 
관련 문제