オプション画面/シーン用に静的セルでグループ化されたUITableView
を使用しています。すべては、Xcode 6.1/iOS 8.1.x/Autolayoutを使用したStoryboardで行われます。テーブルグループ内には、さまざまなタイプのセルがあり、問題を引き起こす2つのタイプがあります。
セル#1で、ラベルと先頭コンテナの間に左マージンの制約を設定できます。セル#2では、私が知る限り、Interface Builderで制約を設定できません。セル#1のラベルに左マージンを設定して、セル#2のラベルと揃えるようにしました。 iPhoneではすべてが正常に見えますが、Table Viewのコンテナーのサイズが画面サイズの半分であるiPadで同じテーブルを表示すると、セル#1は絶対マージンを維持しながら、セル#2のマージンは(動的に?)制約で設定します。また、セル#1の左マージンを「relative to margin」属性で変更しようとしましたが、効果がありません。
iPhone:
iPad(テーブルビュー幅=画面サイズ1/2)
質問は次のとおりです。セル#2のように整列するようにセル#1のラベルに制約を設定するにはどうすればよいですか。
また、問題を示すXcode 6.1サンプルプロジェクトへのリンクもあります。 iPhoneとiPadで実行して、違いを確認します。
https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.Zip
この質問は iPhoneおよびiPadの静的テーブルセルのレイアウト に関連している可能性がありますが、すべてが適応型になっているため、iOS 8でも異なる場合があります。とにかくこの質問を投稿することにしました。
Apple多くのサンプルプロジェクトとスクリーンショットを含むバグ報告チームと戦い、 その答え を分析した後、カスタムスタイルのセルを動作させるソリューションが見つかりました。一貫してマージンに関して、デフォルトのUITableViewCellsと同じように、次のことを行う必要があります(主に Beckyの答え に基づいて、何が違うのか、それが私にとってうまくいったのかを強調しました):
[レイアウトの余白]セクションで、[スーパービューの余白を保持する]をオンにします(プラス記号をクリックしないでください)
(そしてここにキーがあります)セル自体に対して同じを行います(もしそうならコンテンツビューの親)
次のように制約を設定します。Label.Leading = Superview.Leading Margin(定数0)
これで、すべてのセルのラベルがデフォルトのセルと一致するようになりました!これはXcode 7以降で機能し、参照したスレッドに記載されている修正が含まれています。 IBとシミュレーターは、適切に配置されたラベルを表示するはずです。
また、View Controllerのクラスなどで、プログラムでこれを行うこともできます。
cell.preservesSuperviewLayoutMargins = true
cell.contentView.preservesSuperviewLayoutMargins = true
または、起動時にUIAppearanceを1回呼び出すことでセットアップできます(ごめん、Swiftしか知りません)。
UITableViewCell.appearance().preservesSuperviewLayoutMargins = true
UITableViewCell.appearance().contentView.preservesSuperviewLayoutMargins = true
Ethan が親切に指摘したように、UIViewに関するApple自身のドキュメントはpreservesSuperviewLayoutMargins
を次のように説明しています。
このプロパティの値が
true
の場合、コンテンツをレイアウトするときにスーパービューのマージンも考慮されます。このマージンは、ビューのエッジとそのスーパービューの間の距離が対応するマージンよりも小さいレイアウトに影響します。たとえば、フレームがそのスーパービューの境界に正確に一致するコンテンツビューがあるとします。スーパービューのマージンのいずれかがコンテンツビューとそれ自体のマージンで表される領域内にある場合、UIKitはスーパービューのマージンを尊重するようにコンテンツビューのレイアウトを調整します。調整量は、コンテンツがスーパービューのマージン内に収まるようにするために必要な最小量です。
したがって、セルのコンテンツをTableViewのマージン(必要に応じてgreat祖父母)に合わせたい場合は、コンテンツの2つのアセンダントが必要です。 、コンテンツビュー、およびテーブルセル自体は、独自のスーパービューのマージンを保持します。
これがデフォルトの動作ではない理由は私を驚かせます。すべてをカスタマイズしたくないほとんどの開発者は、デフォルトでこの「継承」を期待しているように感じます。
私はあなたと同じ問題に出くわし、解決策を思いつきました。
まず、背景を少し説明します。iOS8以降、デフォルトのテーブルビューセルは、セルの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サブクラスの1つを見ることができます。 https://github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m
乾杯
既存の回答を読んで、明らかなプログラムによる解決策を見つけられなかった後、私はさらに掘り下げて、この問題に直面している他の誰にとっても良い答えを得ました。
まず、preservesSuperviewLayoutMargins
をセルのビューまたはコンテンツビューに otheranswers として設定する必要はありません。デフォルト値はfalse
ですが、true
に変更しても目立った効果はありませんでした。
これを実際に機能させるための鍵は、layoutMarginsGuide
のUIView
プロパティです。この値を使用すると、サブビューのleadingAnchor
をガイドのleadingAnchor
に簡単に固定できます。これがコードでどのように見えるかを示します(そして Jonas's answer のように、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
インセットを使用する必要があります。
注:よりクリーンな構文を希望する場合は、アンカーを少しきれいにするためのライブラリを作成しました。 SuperLayout と呼ばれ、Cocoapodsで利用できます。ソースファイルの先頭で、SuperLayout
をインポートします。
import SuperLayout
次に、レイアウトブロックで、~~
、≤≤
、および≥≥
を使用して制約を固定します。
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
subview1.leadingAnchor ~~ margins.leadingAnchor
subview2.leadingAnchor ~~ margins.leadingAnchor
super.updateConstraints()
}
ios 11+:マージン= contentView.directionalLayoutMarginsにしましょう...そのままLTRとRTLに適応する必要がある場合に備えて。私はほとんどの人がそれを必要とすると思います。
次の操作を行うことにより、標準セルに合わせたカスタムスタイルのセルを取得できました。
これはXcode 7でうまくいきました。 Xcode 6でも機能することを期待しています。
IPad Air、OS 10.1.1でテストするときにこの問題が発生しました。テーブルのヘッダーは本来あるべき位置よりもずっとインデントされており、横向きの場合はさらに悪化しました。しかし、OS 11までのiphoneでは問題ありませんでした。
驚くべき解決策は、テーブルが作成された直後の次のコード行でした(申し訳ありませんが、私はC#でしか作業していませんが、Obj-CとSwift同等のもの)は簡単に解決できます):
myTableView.SeparatorInset = myTableView.SeparatorInset;
その後、すべてが本来のようにインデントされました!