新しいUICollectionViewクラスとUICollectionViewLayoutクラスをいじっています。 UICollectionViewFlowLayoutをサブクラス化して、カスタムレイアウトを作成しました。
セルサイズが動的に変化し、以下のデリゲートメソッドを使用してアイテムサイズを設定します
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
return CGSizeMake(80, 80);
}
次に、カスタムUICollectionViewFlowLayoutクラスのprepareLayoutメソッドの下で、これらのサイズ変数にアクセスして、それらを配置し、layoutAttributesForItemAtIndexPathにキャッシュする方法を計算できるようにする必要があります。
ただし、UICollectionViewまたはUICollectionViewFlowLayoutの下に、デリゲートメソッドで設定したカスタムアイテムのサイズに到達するためのプロパティが見つからないようです。
自分で見つけた。
UICollectionViewDelegateFlowLayout
を省略せずにカスタムクラスを実装する
@interface SECollectionViewCustomLayout : UICollectionViewFlowLayout
<UICollectionViewDelegateFlowLayout>
そして、あなたは呼び出すことができます
CGSize size = [self collectionView:self.collectionView
layout:self
sizeForItemAtIndexPath:indexPath];
さまざまな_UICollectionView...
_ヘッダーファイルを見て、 WWDC 2012セッション219-高度なコレクションビューとカスタムレイアウトの構築 ビデオ(約6:50以降)を見ると、拡張可能なデリゲートパターンのようです動的型付けを利用して、レイアウトが拡張デリゲートメソッドに適切にアクセスできるようにします。
UI(Collection)ViewController
)は、このカスタムプロトコルをサポートするように宣言する必要があります。UICollectionViewFlowLayout
またはそのサブクラスである場合、これは単にUICollectionViewDelegateFlowLayout
への準拠を宣言することを意味します。.m
_したくない場合は、_#import
_ファイルのクラス拡張でこれを自由に実行してください。collectionView
プロパティを使用し、必要なプロトコルに準拠したオブジェクトにデリゲートをキャストして納得させるコンパイラーrespondsToSelector:
_を確認することを忘れないでください。実際、必要に応じて、型キャストによってデリゲートが必要なメソッドを実装することさえ保証されるランタイムがないため、すべてのメソッドでこれを実行しても害はありません。したがって、情報の一部にデリゲートが必要なカスタムレイアウトを実装する場合、ヘッダーは次のようになります。
_@protocol CollectionViewDelegateCustomLayout <UICollectionViewDelegate>
- (BOOL)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)layout
shouldDoSomethingMindblowingAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface CustomLayout : UICollectionViewLayout
// ...
@end
_
あなたのデリゲートは適合を宣言します(私はここの実装ファイルでそうしました):
_#import "CustomLayout.h"
@interface MyCollectionViewController () <CollectionViewDelegateCustomLayout>
@end
@implementation
// ...
- (BOOL)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)layout
shouldDoSomethingMindblowingAtIndexPath:(NSIndexPath *)indexPath
{
return [self canDoSomethingMindblowing];
}
// ...
@end
_
そして、レイアウトの実装では、次のようにメソッドにアクセスします:
_BOOL blowMind;
if ([self.collectionView.delegate respondsToSelector:@selecor(collectionView:layout:shouldDoSomethingMindblowingAtIndexPath:)]) {
blowMind = [(id<CollectionViewDelegateCustomLayout>)self.collectionView.delegate collectionView:self.collectionView
layout:self
shouldDoSomethingMindblowingAtIndexPath:indexPath];
} else {
// Perhaps the layout also has a property for this, if the delegate
// doesn't support dynamic layout properties...?
// blowMind = self.blowMind;
}
_
とにかくデリゲートがそのメソッドに事前に応答することを確認しているので、ここでは型キャストしても安全です。
これは単なる推測にすぎませんが、AppleがUICollectionViewDelegateFlowLayout
プロトコルを管理する方法はこれだと思います。
delegate
プロパティがないため、呼び出しはコレクションビューのデリゲートを経由する必要があります。UICollectionViewController
は、拡張フローレイアウトデリゲートに公に準拠していません(別のプライベートヘッダーでは準拠していないと思います)。UICollectionView
のdelegate
プロパティは、 'base' UICollectionViewDelegate
プロトコルへの準拠のみを宣言します。繰り返しますが、型キャストの必要性を防ぐために、フローレイアウトで使用されているUICollectionView
のプライベートサブクラス/カテゴリがあるとは思いません。この点にさらに重みを付けるには、Appleは、ドキュメント内のサブクラス化UICollectionView
をまったく推奨しません( iOSのコレクションビュープログラミングガイド:カスタムレイアウトの作成 ) :UICollectionViewをサブクラス化しないでください。コレクションビューの外観はほとんどまたはまったくありません。代わりに、データソースオブジェクトからすべてのビューを取得し、レイアウトオブジェクトからすべてのレイアウト関連情報を取得します。
さあ、行きます。複雑ではありませんが、パラダイムに適した方法を実行する方法を知っておく価値はあります。
Swiftバージョンがあります:
self.collectionView(self.collectionView, layout: self.collectionView.collectionViewLayout, sizeForItemAtIndexPath: indexPath)
GitHubで ICollectionView-FlowLayout を確認してください。同じ考え方ですが、これにより、flowLayoutの拡張デリゲートメソッドへのアクセスが少しクリーンになります。
私の場合、レイアウト、セルレイアウトなどに関するすべてがUIViewControllerのnib内とUICollectionViewCellの個別のnib内で定義されています。 MyCollectionViewCell
にはUIImageView
が含まれており、セルに自動レイアウトされ、パディング/マージンが付いていますが、四角形です。
四角形ではなく丸いアイコンが必要ですが、iPhoneとiPadのどちらのペン先を使用するか気にしたくありません(デバイス用と向き用のペン先が別にあります)。
ビューコントローラーに@selector(collectionView:layout:sizeForItemAtIndexPath:)
を実装したくありません。
したがって、collectionView:cellForItemAtIndexPath:
使用できます
CGSize size = cell.imageView.bounds.size;
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = size.height/2.0;
collectionView:layout:sizeForItemAtIndexPath:
の前に呼び出すcollectionView:cellForItemAtIndexPath:
とレイアウトが完了しました。
下の丸いアバターを確認できます
後の読者のために、IOS 7にはそれを定義したUICollectionViewFlowLayoutがあります。