![](/img/trans.png)
[英]UILabel Autolayout ignores UITableViewCell's left margin on iOS 8.1 and 8.2
[英]UITableViewCell with autolayout left margin different on iPhone and iPad
我正在使用帶有靜態單元格的分組UITableView
作為選項屏幕/場景。 一切都在使用Autolayout在Xcode 6.1 / iOS 8.1.x / Storyboard中完成。 在表組中有混合類型的單元格,有兩種類型導致我的問題:
在單元格#1上,我可以為標簽和前導容器之間的左邊距設置約束。 在單元#2上,據我所知,我無法在Interface Builder中設置任何約束。 我在單元格#1中的標簽上設置了左邊距,因此它與單元格#2中的標簽對齊。 iPhone上的一切看起來都不錯,但是如果我在iPad上顯示相同的表格,其中表格視圖的容器大小是屏幕大小的一半,則單元格#2獲得更多邊距(動態?),而單元格#1保持絕對邊距I在約束中設置。 我還嘗試使用屬性“相對於邊距”更改單元格#1中的左邊距,但無效。
蘋果手機:
iPad(桌面寬度= 1/2屏幕尺寸)
所以問題是:如何在單元格#1中設置標簽的約束,使其與單元格#2對齊。
這里還有一個Xcode 6.1示例項目的鏈接,用於演示該問題。 在iPhone和iPad上運行以查看差異:
https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.zip
這個問題可能與iPhone和iPad的布局靜態表格單元格有關 ,但iOS 8也可能有所不同,因為現在一切都應該是自適應的。 這就是我決定發布這個問題的原因。
在與蘋果bug報告團隊進行了多次示例項目和截圖的對抗並解析了這個答案之后 ,我發現讓自定義樣式單元格在其邊距上表現一致的解決方案就像默認的UITableViewCells一樣,你需要做的就是以下(主要基於Becky的回答 ,我突出了它的不同之處以及它對我有用的原因):
在“布局邊距”部分中, 選中“保留超級視圖邊距”(不要單擊加號)
(這是密鑰) 對單元格本身做同樣的事情(內容視圖的父級,如果你願意的話)
按如下方式設置約束: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
正如Ethan所指出的那樣,Apple自己的UIView文檔描述了preservesSuperviewLayoutMargins
,如下所示:
當此屬性的值為
true
,在布置內容時也會考慮superview的邊距。 此邊距會影響視圖邊緣與其超視圖之間的距離小於相應邊距的布局。 例如,您可能有一個內容視圖,其框架精確匹配其超級視圖的邊界。 當superview的任何邊距位於內容視圖所代表的區域內以及它自己的邊距時,UIKit會調整內容視圖的布局以尊重superview的邊距。 調整量是確保內容也在superview的邊距內所需的最小量。
因此,如果您希望單元格的內容與TableView的邊距對齊(如果願意的話,它是非常祖父的),您需要擁有內容的兩個優勢,內容視圖和表格單元本身,保留其自己的超級視圖的邊距。
為什么這不是默認行為讓我感到驚訝:我覺得大多數不想定制所有內容的開發人員都會默認這種“繼承”。
我遇到了和你一樣的問題並提出了解決方案。
首先,一點背景:自iOS 8以來,默認的表格視圖單元格尊重單元格的layoutMargins
以適應不同的特征(又名屏幕又稱設備)。 例如,所有iPhone上的布局邊距(表格中顯示的iPhone 6 Plus除外)為{8, 16, 8, 16}
。 在iPad上他們是{8, 20, 8, 20}
。 所以現在我們知道有4個像素差異,這很可能是你的自定義表視圖單元格不尊重。
當layoutMargins發生更改時,表視圖單元子類需要調整左邊距約束。
這是相關的代碼段:
- (void)layoutMarginsDidChange
{
[super layoutMarginsDidChange];
self.leftLayoutMarginConstraint.constant = self.layoutMargins.left;
self.rightLayoutMarginConstraint.constant = self.layoutMargins.right;
}
通過適應代碼中的布局邊距,您可以始終獲得標題標簽的正確填充。
您還可以看一下我已經尊重layoutMargins的UITableViewCell子類: https : //github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m
干杯
在閱讀了現有的答案而沒有找到明顯的程序化解決方案之后,我做了一些挖掘工作,現在對於面臨這個問題的其他人有了一個很好的答案。
首先,沒有必要像其他 答案所暗示的那樣將preservesSuperviewLayoutMargins
設置為單元格的視圖或內容視圖。 雖然默認值為false
,但將其更改為true
並沒有明顯的效果,我可以看到。
實現此功能的關鍵是UIView
上的layoutMarginsGuide
屬性。 使用此值,我們可以輕松地將leadingAnchor
視圖的leadingAnchor
到指南的leadingAnchor
。 以下是它在代碼中的外觀(很可能就是在Jonas的回答中 ,IB在幕后做的事情)。
在UITableViewCell
子類中,您可以執行以下操作:
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更新
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()
}
就這樣! 如果您正在為iOS 9之前的iOS版本開發,則需要替換布局錨點並使用layoutMargins
inset。
注意:如果您更喜歡更清晰的語法,我編寫了一個庫來使錨點固定更漂亮一點。 它被稱為SuperLayout ,可在Cocoapods上找到。 在源文件的頂部,導入SuperLayout
:
import SuperLayout
然后在你的布局塊中,使用~~
, ≤≤
和≥≥
來限制約束:
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
subview1.leadingAnchor ~~ margins.leadingAnchor
subview2.leadingAnchor ~~ margins.leadingAnchor
super.updateConstraints()
}
ios 11+:讓margins = contentView.directionalLayoutMargins ...以防你需要適應LTR和RTL。 我假設大多數人確實需要這樣做。
通過執行以下操作,我能夠將自定義樣式的單元格與標准單元格對齊:
這在Xcode 7中對我有用; 我希望它也適用於Xcode 6。
我在iPad Air,OS 10.1.1上測試時遇到了這個問題。 表格標題的縮進程度遠遠超過它們應有的程度,而且在橫向方向上更糟糕。 但他們在iphone到OS 11之前都很好。
令人驚訝的解決方案是在創建表之后的以下代碼行(對不起,我只使用C#,但很容易找出Obj-C和Swift等價物):
myTableView.SeparatorInset = myTableView.SeparatorInset;
然后一切都縮進了它應該是!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.