簡體   English   中英

在iPhone和iPad上具有自動布局左邊距的UITableViewCell不同

[英]UITableViewCell with autolayout left margin different on iPhone and iPad

我正在使用帶有靜態單元格的分組UITableView作為選項屏幕/場景。 一切都在使用Autolayout在Xcode 6.1 / iOS 8.1.x / Storyboard中完成。 在表組中有混合類型的單元格,有兩種類型導致我的問題:

  1. 具有自定義樣式的單元格
  2. 樣式為“右側細節”的單元格

在單元格#1上,我可以為標簽和前導容器之間的左邊距設置約束。 在單元#2上,據我所知,我無法在Interface Builder中設置任何約束。 我在單元格#1中的標簽上設置了左邊距,因此它與單元格#2中的標簽對齊。 iPhone上的一切看起來都不錯,但是如果我在iPad上顯示相同的表格,其中表格視圖的容器大小是屏幕大小的一半,則單元格#2獲得更多邊距(動態?),而單元格#1保持絕對邊距I在約束中設置。 我還嘗試使用屬性“相對於邊距”更改單元格#1中的左邊距,但無效。

蘋果手機:

iPhone上的表格

iPad(桌面寬度= 1/2屏幕尺寸)

iPad上的表格

所以問題是:如何在單元格#1中設置標簽的約束,使其與單元格#2對齊。

這里還有一個Xcode 6.1示例項目的鏈接,用於演示該問題。 在iPhone和iPad上運行以查看差異:

https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.zip

這個問題可能與iPhone和iPad的布局靜態表格單元格有關 ,但iOS 8也可能有所不同,因為現在一切都應該是自適應的。 這就是我決定發布這個問題的原因。

如何解決它

在與蘋果bug報告團隊進行了多次示例項目和截圖的對抗並解析了這個答案之后 ,我發現讓自定義樣式單元格在其邊距上表現一致的解決方案就像默認的UITableViewCells一樣,你需要做的就是以下(主要基於Becky的回答 ,我突出了它的不同之處以及它對我有用的原因):

  1. 在IB中選擇單元格的內容視圖
  2. 轉到尺寸檢查器
  3. 在“布局邊距”部分中, 選中“保留超級視圖邊距”(不要單擊加號)

    檢查保留超視圖邊距

  4. (這是密鑰) 對單元格本身做同樣的事情(內容視圖的父級,如果你願意的話)

    這次是單元格而不是內容視圖

  5. 按如下方式設置約束: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。 我假設大多數人確實需要這樣做。

通過執行以下操作,我能夠將自定義樣式的單元格與標准單元格對齊:

  1. 在“文檔大綱”中,為具有自定義樣式的單元格選擇“內容視圖”。
  2. 轉到尺寸檢查器。
  3. 在“布局邊距”下拉列表中,點擊“保留Superview邊距”旁邊的小加號。
  4. 選擇iPad尺寸等級,即“常規寬度x常規高度”。
  5. 選中“保留Superview邊距”旁邊的復選框。
  6. 通過更新幀來解決任何自動布局警告。

這在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM