[解決済み】UICollectionView 自動レイアウトでセルサイズを変更する方法
質問
セルフサイジングに挑戦しています
UICollectionViewCells
Auto Layout で動作していますが、セルのサイズをコンテンツに合わせられないようです。セルのサイズが、セルのcontentViewの中の内容からどのように更新されるのか理解するのに苦労しています。
私が試した設定は以下の通りです。
-
カスタム
UICollectionViewCell
を持つUITextView
をそのcontentViewに追加します。 -
をスクロールさせる。
UITextView
は無効です。 -
contentViewの水平方向の制約は、"H:|[_textView(320)]"であり、つまりは
UITextView
は、明示的に幅が320のセルの左側に固定されます。 -
contentViewの垂直方向の制約は、"V:|-0-[_textView]"であり、すなわち
UITextView
セルの上部に固定されます。 -
は、その
UITextView
は高さの制約を定数に設定し、それをUITextView
がテキストにフィットすることを報告します。
セルの背景を赤に設定し、さらに
UITextView
の背景をBlueに設定します。
今まで遊んでいたプロジェクトをGitHubに置いてみました こちら .
解決方法は?
<ブロッククオートこの回答は、コンポジションレイアウトが追加されたiOS 14から古くなったものです。を更新することをご検討ください。 新規API
Swift 5に対応したアップデート
preferredLayoutAttributesFittingAttributes
に改名されました。
preferredLayoutAttributesFitting
で、オートサイジングを使用する
Swift 4に対応したアップデート
systemLayoutSizeFittingSize
に改名されました。
systemLayoutSizeFitting
iOS 9に対応したアップデート
私のGitHubのソリューションがiOS 9で壊れるのを見た後、私はようやくこの問題を完全に調査する時間を得ました。現在、レポを更新し、セルフサイジングセルのさまざまな設定の例をいくつか含んでいます。私の結論は、セルフサイジングセルは理論的には素晴らしいが、実際には厄介であるということです。セルフサイジングセルを使用する際には注意が必要です。
TL;DR
私のチェックアウト GitHubプロジェクト
セルフサイズセルはフローレイアウトでのみサポートされています。
セルフサイジングセルを動作させるには、2つの設定を行う必要があります。
#1. 設定
estimatedItemSize
オン
UICollectionViewFlowLayout
を設定すると、フローレイアウトがダイナミックになります。
estimatedItemSize
プロパティを使用します。
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
#2. セルのサブクラスでサイジングのサポートを追加する
これには2つの種類があります; 自動レイアウト
または
のカスタムオーバーライドです。
preferredLayoutAttributesFittingAttributes
.
オートレイアウトでセルを作成・設定する
この点に関しては、優れた
SOの記事
セルに対する制約の設定について。ただ、注意しなければならないのは
Xcode 6 が壊れた
iOS 7をサポートする場合、セルのcontentViewにautoresizingMaskを設定し、セルが読み込まれたときにcontentViewの境界がセルの境界として設定されるようにする必要があります(例.
awakeFromNib
).
注意しなければならないのは、セルはテーブルビューセルよりも深刻な制約を受ける必要があることです。例えば、幅をダイナミックにしたい場合、セルには高さの制約が必要です。同様に、高さを動的にしたい場合は、セルに幅の制約が必要です。
実装
preferredLayoutAttributesFittingAttributes
をカスタムセルで使用します。
この関数が呼ばれたとき、ビューにはすでにコンテンツが設定されています (例.
cellForItem
が呼び出されました)。制約が適切に設定されていると仮定すると、次のような実装が可能です。
//forces the system to do one layout pass
var isHeightCalculated: Bool = false
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//Exhibit A - We need to cache our calculation to prevent a crash.
if !isHeightCalculated {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var newFrame = layoutAttributes.frame
newFrame.size.width = CGFloat(ceilf(Float(size.width)))
layoutAttributes.frame = newFrame
isHeightCalculated = true
}
return layoutAttributes
}
ノート
iOS 9では動作が少し変わり、気をつけないと実装がクラッシュする可能性があります(詳細はこちら
こちら
). 実装する場合
preferredLayoutAttributesFittingAttributes
の場合、レイアウト属性のフレームを一度だけ変更することを保証する必要があります。これを行わないと、レイアウトはあなたの実装を無限に呼び出し、最終的にはクラッシュします。一つの解決策は、計算されたサイズをセル内にキャッシュし、セルを再利用したり、その内容を変更したりするときはいつでもこれを無効にすることで、これは私が
isHeightCalculated
プロパティを指定します。
レイアウトを体験する
この時点で、collectionViewに「機能する」ダイナミックセルがあるはずです。私はテスト中に、すぐに使える解決策をまだ見つけていないので、もし見つけた場合は遠慮なくコメントしてください。まだ
UITableView
は、ダイナミックサイジングの戦いに勝つと私は思います。
#キャバ嬢
プロトタイプセルを使用して推定アイテムサイズを計算する場合、以下のような問題が発生することに注意してください。
XIB はサイズクラスを使用します。
. この理由は、XIB からセルを読み込むと、そのサイズクラスが次のように設定されるからです。
Undefined
. iOS 7 では、サイズクラスはデバイスに基づいて読み込まれるため(iPad = Regular-Any、iPhone = Compact-Any)、これは iOS 8 以降でのみ壊れるでしょう。XIBをロードせずにestimatedItemSizeを設定するか、XIBからセルをロードしてcollectionViewに追加し(これはtraitCollectionを設定します)、レイアウトを実行して、スーパービューからそれを削除することができます。また、セルに
traitCollection
を取得し、適切な形質を返します。それはあなた次第です。
もし何か見逃したものがあれば教えてください。お役に立てれば幸いです。
関連
-
[解決済み】Xcode 10.2.1 Command PhaseScriptExecutionが0以外の終了コードで失敗した。
-
[解決済み】arm64アーキテクチャの未定義シンボルについて
-
[解決済み] Xcode コマンド /usr/bin/codesign は終了コード 1 で失敗しました : errSecInternalComponent
-
[解決済み] シミュレーターiOS 13でダークモードを使用するには?
-
[解決済み] 基本的なUIButtonをプログラムで作成するには?
-
[解決済み] UITabBar アイコンが正しく表示されない
-
[解決済み] Swiftを使って音を鳴らすには?
-
[解決済み] ERROR ITMS-9000: "Redundant Binary Upload. 列車 '1.0' のビルドバージョン '1.0' のバイナリアップロードが既に存在します" と表示されました。
-
[解決済み] NSIntegerからNSStringデータ型に変換するにはどうすればよいですか?
-
[解決済み] UIViewAlertForUnsatisfiableConstraintsでトラップする方法は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】リンカーコマンドが終了コード1で失敗(起動を確認するには-vを使用)、Xcode 8、Swift 3
-
[解決済み】印刷します。エントリ, ":CFBundleIdentifier", Does Not Exist
-
[解決済み】"宣言はファイルスコープでのみ有効 "について
-
[解決済み] Xcode は、[バンドル ID] に一致する iOS App Store プロビジョニングプロファイルを見つけられませんでした。
-
[解決済み] Xcodeエラー "Could not find Developer Disk Image" が発生する。
-
[解決済み] 警告: 'characters' は非推奨です。String または Substring を直接使用してください。
-
[解決済み] このアクションは完了できませんでした。再試行 (-22421)
-
[解決済み] アラート "デバッグを続けるには、開発者ツールへのアクセスが他のプロセスの制御を必要とします。これを許可するにはパスワードを入力してください。
-
[解決済み] 'CGPointMake' は swift で使用できません [重複] 。
-
[解決済み] UICollectionView、全幅のセル、オートレイアウトの動的な高さを許可しますか?