iPhone 및 iPad에서 자동 레이아웃 왼쪽 여백이 다른 UITableViewCell
UITableView
옵션 화면 / 장면에 정적 셀 그룹 을 사용하고 있습니다. 모든 작업은 자동 레이아웃을 사용하여 Xcode 6.1 / iOS 8.1.x / Storyboard에서 수행됩니다. 테이블 그룹에는 혼합 된 유형의 셀이 있으며 문제를 일으키는 두 가지 유형이 있습니다.
- 사용자 정의 스타일 및
- 스타일이 "오른쪽 세부 사항"인 셀
셀 # 1에서 레이블과 선행 컨테이너 사이의 왼쪽 여백에 대한 제약 조건을 설정할 수 있습니다. 셀 # 2에서 내가 아는 한 Interface Builder에서 제약 조건을 설정할 수 없습니다. 셀 # 1의 레이블에 왼쪽 여백을 설정하여 셀 # 2의 레이블과 맞 춥니 다. iPhone에서는 모든 것이 괜찮아 보이지만 테이블 뷰의 컨테이너 크기가 화면 크기의 절반 인 iPad에서 동일한 테이블을 표시하면 셀 # 2가 더 많은 여백 (동적으로?)을 얻는 반면 셀 # 1은 절대 여백을 유지합니다. 제약에 설정합니다. 또한 "relative to margin"속성을 사용하여 셀 # 1의 왼쪽 여백을 변경하려고했지만 아무 소용이 없었습니다.
iPhone :
iPad (Tableview 너비 = 1/2 화면 크기)
따라서 질문은 다음과 같습니다. 셀 # 1의 레이블에 대한 제약 조건을 어떻게 설정하여 셀 # 2처럼 정렬되도록합니다.
여기에 문제를 보여주는 Xcode 6.1 샘플 프로젝트에 대한 링크도 있습니다. iPhone 및 iPad에서 실행하여 차이점을 확인하십시오.
https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.zip
이 질문은 iPhone 및 iPad 용 레이아웃 정적 테이블 셀 과 관련이있을 수 있지만 모든 것이 이제 적응해야하기 때문에 iOS 8에서도 다를 수 있습니다. 그래서 어쨌든이 질문을 게시하기로 결정했습니다.
그것을 고치는 방법
많은 샘플 프로젝트와 스크린 샷으로 애플 버그보고 팀과 싸우고 그 답변을 분석 한 후 사용자 지정 스타일 셀이 여백과 관련하여 일관되게 작동하고 기본 UITableViewCells처럼 동작하도록하는 솔루션이 있다는 것을 발견했습니다. 다음 (주로 Becky의 답변을 기반으로하여 무엇이 다른지 그리고 무엇이 나를 위해 작동하게 만들 었는지 강조했습니다) :
- IB에서 셀의 콘텐츠보기 선택
- 크기 검사기로 이동
레이아웃 여백 섹션에서 Superview 여백 유지를 선택합니다 (더하기 기호를 클릭하지 마십시오).
(그리고 여기에 핵심이 있습니다) 셀 자체에 대해 동일 하게 수행하십시오 (원하는 경우 콘텐츠보기의 상위 항목).
제약 조건을 다음과 같이 설정하십시오. Label.Leading = Superview.Leading Margin (상수 0)
이제 모든 셀에 기본 셀과 일치하는 레이블이 있습니다! 이것은 Xcode 7 이상에서 나를 위해 작동하며 내가 언급 한 스레드에서 언급 한 수정 사항을 포함합니다. 이제 IB와 시뮬레이터에 올바르게 정렬 된 레이블이 표시됩니다.
예를 들어 View Controller의 클래스에서 프로그래밍 방식으로이 중 일부를 수행 할 수도 있습니다.
cell.preservesSuperviewLayoutMargins = true
cell.contentView.preservesSuperviewLayoutMargins = true
또는 시작할 때 UIAppearance를 한 번 호출하여 설정할 수 있습니다 (Swift 만 알고 있습니다, 죄송합니다).
UITableViewCell.appearance().preservesSuperviewLayoutMargins = true
UITableViewCell.appearance().contentView.preservesSuperviewLayoutMargins = true
작동 원리와 이유
로 이든이 친절하게 지적하여 UIView에 애플의 문서는 설명 preservesSuperviewLayoutMargins
으로 다음과 같습니다 :
When the value of this property is
true
, the superview’s margins are also considered when laying out content. This margin affects layouts where the distance between the edge of a view and its superview is smaller than the corresponding margin. For example, you might have a content view whose frame precisely matches the bounds of its superview. When any of the superview’s margins is inside the area represented by the content view and its own margins, UIKit adjusts the content view’s layout to respect the superview’s margins. The amount of the adjustment is the smallest amount needed to ensure that content is also inside the superview’s margins.
Therefore, if you want your cell's content to align with the TableView's margins (it's great-grandparent if you will), you need to have your content's two ascendants, Content View and the Table Cell itself, preserve the margins of their own superview.
Why this isn't default behavior surprises me : I feel like most developers who don't want to customize everything would expect this "inheritance" by default.
I ran in the same problem as you did and came up with a solution.
First, a little background: Since iOS 8, default table view cells respect the cell's layoutMargins
to adapt for different traits (aka screens aka devices). For instance, layout margins on all iPhones (except iPhone 6 Plus when shown in a form sheet) are {8, 16, 8, 16}
. On iPad they're {8, 20, 8, 20}
. So now we know that there 4 pixels difference, which most likely your custom table view cell doesn't respect.
Your table view cell subclass needs to adapt the left margin constraint when layoutMargins change.
Here's the relevant code snippet:
- (void)layoutMarginsDidChange
{
[super layoutMarginsDidChange];
self.leftLayoutMarginConstraint.constant = self.layoutMargins.left;
self.rightLayoutMarginConstraint.constant = self.layoutMargins.right;
}
Adapting to the layout margins in code enables you getting always the right padding for your title label.
You may also take a look at one of my UITableViewCell subclasses that already respect layoutMargins: https://github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m
Cheers
After reading through the existing answers and not finding an obvious programmatic solution, I did some more digging and now have a good answer for anyone else facing this issue.
First off, it's not necessary to set preservesSuperviewLayoutMargins
to the cell's view or content view as other answers imply. While the default value is false
, changing it to true
had no noticeable effect that I could see.
The key for making this actually work is the layoutMarginsGuide
property on UIView
. Using this value, we can just easily pin the leadingAnchor
of any subview to the leadingAnchor
of the guide. Here's how it looks in code (and may very well be what IB is doing behind the scenes as in Jonas's answer).
In a UITableViewCell
subclass, you would do something like this:
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
let leading = margins.leadingAnchor
subview1.leadingAnchor.constraintEqualToAnchor(leading).active = true
subview2.leadingAnchor.constraintEqualToAnchor(leading).active = true
super.updateConstraints()
}
Swift 4.1 update
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
let leading = margins.leadingAnchor
subview1.leadingAnchor.constraint(equalTo: leading).isActive = true
subview2.leadingAnchor.constraint(equalTo: leading).isActive = true
super.updateConstraints()
}
That's all! If you're developing for iOS versions pre-iOS 9, you'll need to substitute out the layout anchors and use the layoutMargins
inset instead.
Note: I wrote a library to make the anchor pinning a little prettier, if you'd prefer a cleaner syntax. It's called SuperLayout and is available on Cocoapods. At the top of your source file, import SuperLayout
:
import SuperLayout
And then in your layout block, use ~~
, ≤≤
, and ≥≥
to pin constraints:
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
subview1.leadingAnchor ~~ margins.leadingAnchor
subview2.leadingAnchor ~~ margins.leadingAnchor
super.updateConstraints()
}
ios 11+: let margins = contentView.directionalLayoutMargins ... in case you need to adapt to LTR and RTL out of the box. I assume most folks do need that.
I was able to get cells with custom styles aligned with the standard cells by doing the following:
- In the Document Outline, select the "Content View" for the cell with the custom style.
- Go to the Size Inspector.
- Under the "Layout Margins" dropdown, hit the little plus symbol next to "Preserve Superview Margins."
- Select the iPad size class, which is "Regular Width x Regular Height."
- Check the checkbox next to "Preserve Superview Margins."
- Resolve any Auto Layout warnings by updating the frames.
이것은 Xcode 7에서 나를 위해 일했습니다. Xcode 6에서도 작동하기를 바랍니다.
iPad Air, OS 10.1.1에서 테스트 할 때이 문제가 발생했습니다. 표 머리글은 원래 있어야하는 것보다 훨씬 더 들여 쓰기가되었으며 가로 방향에서는 더 나빴습니다. 그러나 OS 11까지의 아이폰에서는 괜찮 았습니다.
놀라운 해결책은 테이블이 생성 된 직후에 다음과 같은 코드 줄이었습니다 (죄송합니다. 저는 C #에서만 작업하지만 Obj-C 및 Swift 등가물을 쉽게 해결할 수 있습니다).
myTableView.SeparatorInset = myTableView.SeparatorInset;
그런 다음 모든 것이 들여 쓰기되었습니다!
'programing tip' 카테고리의 다른 글
문자열에 알파벳 문자가 포함되어 있는지 Javascript에서 확인하는 방법 (0) | 2020.12.03 |
---|---|
부트 스트랩 모달을 더 넓게 만들려고 (0) | 2020.12.03 |
순수한 CSS 3 차원 구체를 어떻게 만들 수 있습니까? (0) | 2020.12.03 |
여러 병을 결합하는 깨끗한 방법? (0) | 2020.12.03 |
포스트 백에서 Page_Init 이벤트에서 어떤 컨트롤이 포스트 백을 유발하는지 어떻게 확인할 수 있습니까? (0) | 2020.12.03 |