UICollectionView
を持つUICollectionViewFlowLayout
があり、そのコンテンツサイズを計算したい(AutoLayoutで高さを調整するために必要なintrinsicContentSize
を返すため)。
問題は、すべてのセルの高さが同じで固定されていても、UICollectionView
にある「行」/行の数がわかりません。また、データアイテムを表すセルの幅が異なるため、データソース内のアイテムの数でそのカウントを決定することもできません。したがって、UICollectionView
の1行にあるアイテムの数も異なります。
公式ドキュメントでこのトピックに関するヒントを見つけることができなかったため、グーグルでこれ以上説明しなかったため、ヘルプやアイデアをいただければ幸いです。
おっ!なんらかの理由で、数時間の調査の後、私の質問に対する非常に簡単な答えを見つけました。UICollectionView
で見つけることができるすべてのドキュメントを掘り下げて、間違った場所で完全に検索していました。
シンプルで簡単な解決策は、基礎となるレイアウトにあります。myCollectionView.collectionViewLayout
プロパティでcollectionViewContentSize
を呼び出すだけで、コンテンツの高さと幅をCGSize
として取得できます。それは簡単です。
自動レイアウトを使用している場合、UICollectionView
のサブクラスを作成できます
以下のコードを使用する場合、コレクションビューの内容に基づいて変化するため、コレクションビューの高さの制約を指定する必要はありません。
以下に実装を示します。
@interface DynamicCollectionView : UICollectionView
@end
@implementation DynamicCollectionView
- (void) layoutSubviews
{
[super layoutSubviews];
if (!CGSizeEqualToSize(self.bounds.size, [self intrinsicContentSize]))
{
[self invalidateIntrinsicContentSize];
}
}
- (CGSize)intrinsicContentSize
{
CGSize intrinsicContentSize = self.contentSize;
return intrinsicContentSize;
}
@end
viewDidAppear
では、次の方法で入手できます。
float height = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;
データをリロードし、新しいデータで新しい高さを計算する必要がある場合は、次の方法で取得できます:CollectionView
がviewdidload
でデータのリロードを終了したときにリッスンするオブザーバーを追加します
[self.myCollectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];
次に、以下の関数を追加して、新しい高さを取得するか、collectionviewのリロードが完了した後に何かを実行します。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
//Whatever you do here when the reloadData finished
float newHeight = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;
}
そして、オブザーバーを削除することを忘れないでください:
[self.myCollectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];
swiftでuser1046037の答え...
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if bounds.size != intrinsicContentSize() {
invalidateIntrinsicContentSize()
}
}
override func intrinsicContentSize() -> CGSize {
return self.contentSize
}
}
User1046037の回答のSwift 3コード
import UIKit
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return contentSize
}
}
スイフト4
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return collectionViewLayout.collectionViewContentSize
}
}
Swift 4.2
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if bounds.size != intrinsicContentSize {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return self.contentSize
}
}
Swift 4.2、Xcode 10.1、iOS 12.1:
何らかの理由で、collectionView.contentSize.height
がコレクションビューの解決された高さよりも小さく表示されていました。最初に、スーパービューの高さの1/2に対して自動レイアウト制約を使用していました。 これを修正するために、ビューの「安全な領域」に関連するように制約を変更しました。
これにより、collectionView.contentSize.height
を使用してコレクションビューに合わせてセルの高さを設定できました。
private func setCellSize() {
let height: CGFloat = (collectionView.contentSize.height) / CGFloat(numberOfRows)
let width: CGFloat = view.frame.width - CGFloat(horizontalCellMargin * 2)
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSize(width: width, height: height)
}
Before
After
@ user1046037の迅速なバージョン:
public class DynamicCollectionView: UICollectionView {
override public func layoutSubviews() {
super.layoutSubviews()
if !bounds.size.equalTo(intrinsicContentSize) {
invalidateIntrinsicContentSize()
}
}
override public var intrinsicContentSize: CGSize {
let intrinsicContentSize: CGSize = contentSize
return intrinsicContentSize
}
}
さらに、高さを取得する前にreloadData
を呼び出した方がよいでしょう:myCollectionView.collectionViewLayout.collectionViewContentSize