UICollectionView
のセクションにセル間隔を設定するにはどうすればいいですか?私はそれを5.0に設定したminimumInteritemSpacing
プロパティがあることを私は知っていますまだスペースは5.0に現れていません。フローデリゲートメソッドを実装しました。
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 5.0;
}
それでも私は望んだ結果を得ていません。私はそれが最小の間隔だと思います。最大間隔を設定できる方法はありませんか。
このトピックは古くからあると私は知っていますが、万が一誰かがまだ正しい答えを必要としている場合に備えて、あなたが必要としているもの:
そのような実装を追加します。
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *answer = [super layoutAttributesForElementsInRect:rect];
for(int i = 1; i < [answer count]; ++i) {
UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
NSInteger maximumSpacing = 4;
NSInteger Origin = CGRectGetMaxX(prevLayoutAttributes.frame);
if(Origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
CGRect frame = currentLayoutAttributes.frame;
frame.Origin.x = Origin + maximumSpacing;
currentLayoutAttributes.frame = frame;
}
}
return answer;
}
maximumSpacingは任意の値に設定できます。このトリックは、セル間のスペースがmaximumSpacingと完全に等しくなることを保証します。
最初の質問を支持する。私はUICollectionView
で5pxの間隔を取ろうとしましたが、これはUIEdgeInsetsMake(0,0,0,0)
...と同様にうまくいきません。
UITableViewで私は直接行のx、y座標を指定することによってこれを行うことができます...
私のUICollectionViewコードがあります。
#pragma mark collection view cell layout / size
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return [self getCellSize:indexPath]; // will be w120xh100 or w190x100
// if the width is higher, only one image will be shown in a line
}
#pragma mark collection view cell paddings
- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(0, 0, 0, 0); // top, left, bottom, right
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 5.0;
}
#import "ViewController.h"
#import "MagazineCell.h" // created just the default class.
static NSString * const cellID = @"cellID";
@interface ViewController ()
@end
@implementation ViewController
#pragma mark - Collection view
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 30;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
mCell.backgroundColor = [UIColor lightGrayColor];
return mCell;
}
#pragma mark Collection view layout things
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
CGSize mElementSize = CGSizeMake(104, 104);
return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
@end
水平フローレイアウトを使用して、セル間の間隔も10ポイントになりました。スペースを削除するには、minimumLineSpacing
とminimumInterItemSpacing
をゼロに設定する必要がありました。
UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
flow.itemSize = CGSizeMake(cellWidth, cellHeight);
flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flow.minimumInteritemSpacing = 0;
flow.minimumLineSpacing = 0;
また、すべてのセルが同じサイズの場合は、デリゲートメソッドを使用するのではなく、フローレイアウトにプロパティを直接設定するほうが簡単で効率的です。
覚えておいて、それは最小行スペースであり、最小項目間スペースやセルスペースではありません。あなたのコレクションビューのスクロール方向は水平です。
垂直方向の場合は、セル間の水平方向のスペースにセルスペースまたは項目間スペースを、セル間の垂直方向のスペースに行間を設定する必要があります。
Objective-Cのバージョン
- (CGFloat)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 20;
}
Swift版:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 20
}
このコードを試して、各項目間に5pxの間隔を空けてください。
- (UIEdgeInsets)collectionView:(UICollectionView *) collectionView
layout:(UICollectionViewLayout *) collectionViewLayout
insetForSectionAtIndex:(NSInteger) section {
return UIEdgeInsetsMake(0, 0, 0, 5); // top, left, bottom, right
}
- (CGFloat)collectionView:(UICollectionView *) collectionView
layout:(UICollectionViewLayout *) collectionViewLayout
minimumInteritemSpacingForSectionAtIndex:(NSInteger) section {
return 5.0;
}
最も人気のある答えのSwiftバージョン。セル間のスペースはcellSpacing
と等しくなります。
class CustomViewFlowLayout : UICollectionViewFlowLayout {
let cellSpacing:CGFloat = 4
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
if let attributes = super.layoutAttributesForElementsInRect(rect) {
for (index, attribute) in attributes.enumerate() {
if index == 0 { continue }
let prevLayoutAttributes = attributes[index - 1]
let Origin = CGRectGetMaxX(prevLayoutAttributes.frame)
if(Origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
attribute.frame.Origin.x = Origin + cellSpacing
}
}
return attributes
}
return nil
}
}
プロパティ名minimumInterItemSpacingに注意してください。これは、項目間の最小間隔になります正確な間隔ではありません。 minimumInterItemSpacingを何らかの値に設定した場合、間隔がそれより小さい値にならないようにすることができます。しかしより高い価値を得るチャンスがあります。
実際には、項目間の間隔はいくつかの要因itemSizeとsectionInsetによって異なります。コレクションビューは、これらの値に基づいてコンテンツを動的に配置します。だからあなたは正確な間隔を保証することはできません。 sectionInsetおよびminimumInterItemSpacingを使用して、試行錯誤してください。
Swift 3.0、Xcode 8に対する回答
1.コレクションビューデリゲートを必ず設定してください。
class DashboardViewController: UIViewController {
@IBOutlet weak var dashboardCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
dashboardCollectionView.delegate = self
}
}
2.実装UICollectionViewDelegateFlowLayoutプロトコル、UICollectionViewDelegateではありません。
extension DashboardViewController: UICollectionViewDelegateFlowLayout {
fileprivate var sectionInsets: UIEdgeInsets {
return .zero
}
fileprivate var itemsPerRow: CGFloat {
return 2
}
fileprivate var interitemSpace: CGFloat {
return 5.0
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let sectionPadding = sectionInsets.left * (itemsPerRow + 1)
let interitemPadding = max(0.0, itemsPerRow - 1) * interitemSpace
let availableWidth = collectionView.bounds.width - sectionPadding - interitemPadding
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem, height: widthPerItem)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return interitemSpace
}
}
投票回答 (および Swiftバージョン )には小さな問題があります。 :右側に大きな間隔があります。
これは、フローレイアウトがセルの間隔を正確にするようにカスタマイズされており、float leftの動作をしているためです。
私の解決策はセクションのインセットを操作して、セクションが中央に揃うようにしても、間隔は指定されたとおりになるようにすることです。
下のスクリーンショットでは、項目と行の間隔は正確に8ptですが、左右のセクションの挿入部分は8ptより大きくなります(中央揃えにするため)。
そのように迅速なコード:
private let minItemSpacing: CGFloat = 8
private let itemWidth: CGFloat = 100
private let headerHeight: CGFloat = 32
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Create our custom flow layout that evenly space out the items, and have them in the center
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
layout.minimumInteritemSpacing = minItemSpacing
layout.minimumLineSpacing = minItemSpacing
layout.headerReferenceSize = CGSize(width: 0, height: headerHeight)
// Find n, where n is the number of item that can fit into the collection view
var n: CGFloat = 1
let containerWidth = collectionView.bounds.width
while true {
let nextN = n + 1
let totalWidth = (nextN*itemWidth) + (nextN-1)*minItemSpacing
if totalWidth > containerWidth {
break
} else {
n = nextN
}
}
// Calculate the section inset for left and right.
// Setting this section inset will manipulate the items such that they will all be aligned horizontally center.
let inset = max(minItemSpacing, floor( (containerWidth - (n*itemWidth) - (n-1)*minItemSpacing) / 2 ) )
layout.sectionInset = UIEdgeInsets(top: minItemSpacing, left: inset, bottom: minItemSpacing, right: inset)
collectionView.collectionViewLayout = layout
}
スペースの簡単なコード
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 10 // Some float value
ヘッダファイルでUICollectionViewDelegateFlowLayout
プロトコルを定義してください。
このようにUICollectionViewDelegateFlowLayout
プロトコルの以下のメソッドを実装します。
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(5, 5, 5, 5);
}
ここをクリック して、アップルのマニュアルUIEdgeInsetMake
メソッドを参照してください。
私はmonotouchを使用しているので、名前とコードは少し異なりますが、コレクションビューの幅が(x * cell width)+(x-1)* MinimumSpacing with x = amountになるようにすることでこれを実行できます行あたりのセル数。
MinimumInteritemSpacingとセルの幅に基づいて次の手順を実行してください。
1)セルサイズ+現在のインセット+最小間隔に基づいて、1行あたりのアイテム数を計算します。
float currentTotalWidth = CollectionView.Frame.Width - Layout.SectionInset.Left - Layout.SectionInset.Right (Layout = flowlayout)
int amountOfCellsPerRow = (currentTotalWidth + MinimumSpacing) / (cell width + MinimumSpacing)
2)これで、コレクションビューの予想幅を計算するためのすべての情報が得られました。
float totalWidth =(amountOfCellsPerRow * cell width) + (amountOfCellsPerRow-1) * MinimumSpacing
3)つまり、現在の幅と予想される幅の差は
float difference = currentTotalWidth - totalWidth;
4)インセットを調整します(この例では右側に追加しているので、コレクションビューの左側の位置は同じままです)
Layout.SectionInset.Right = Layout.SectionInset.Right + difference;
上記の解決方法 による vojtech-vrbka は正しいですが、それは警告をトリガーします:
警告:UICollectionViewFlowLayoutがインデックスパスとフレームの不一致をキャッシュしています - キャッシュされた値:フローレイアウトサブクラスLayoutが、コピーせずにUICollectionViewFlowLayoutから返される属性を変更するために発生する可能性があります
次のコードで修正する必要があります。
class CustomViewFlowLayout : UICollectionViewFlowLayout {
let cellSpacing:CGFloat = 4
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let original = super.layoutAttributesForElementsInRect(rect)
if let original = original {
let attributes = NSArray.init(array: original, copyItems: true) as! [UICollectionViewLayoutAttributes]
for (index, attribute) in attributes.enumerate() {
if index == 0 { continue }
let prevLayoutAttributes = attributes[index - 1]
let Origin = CGRectGetMaxX(prevLayoutAttributes.frame)
if(Origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
attribute.frame.Origin.x = Origin + cellSpacing
}
}
return attributes
}
return nil
}
}
実際のセルサイズに触れずに間隔を微調整したい場合は、これが私にとって最適な解決策です。 #xcode 9#tvOS11#iOS11#スウィフト
そのため、UICollectionViewDelegateFlowLayoutでは、次のメソッドを変更して実装してください。その方向。 :D
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return cellSpacing
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return cellSpacing
}
私はOPと同じような問題を見つけました。残念ながら、受け入れられた答えは私にとってはうまくいきませんでした。なぜならcollectionView
の内容は正しく中央揃えされていないからです。そのため、collectionView
内のすべての項目が同じ幅であることのみを要求する別の解決策を思いつきました。
#define cellSize 90
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
float width = collectionView.frame.size.width;
float spacing = [self collectionView:collectionView layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
int numberOfCells = (width + spacing) / (cellSize + spacing);
int inset = (width + spacing - numberOfCells * (cellSize + spacing) ) / 2;
return UIEdgeInsetsMake(0, inset, 0, inset);
}
そのコードは...minimumInteritemSpacing...
によって返される値がすべてのcollectionViewCell
間の正確な間隔になることを保証し、さらにすべてのセルがcollectionView
の中央にくることを保証します。
Iago849の答えを試してみましたが、うまくいきました。
スイフト4
open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let answer = super.layoutAttributesForElements(in: rect) else {
return nil
}
let count = answer.count
for i in 1..<count {
let currentLayoutAttributes = answer[i]
let prevLayoutAttributes = answer[i-1]
let Origin = prevLayoutAttributes.frame.maxX
if (Origin + CGFloat(spacing) + currentLayoutAttributes.frame.size.width) < self.collectionViewContentSize.width && currentLayoutAttributes.frame.Origin.x > prevLayoutAttributes.frame.Origin.x {
var frame = currentLayoutAttributes.frame
frame.Origin.x = Origin + CGFloat(spacing)
currentLayoutAttributes.frame = frame
}
}
return answer
}
これがgithubプロジェクトへのリンクです。 https://github.com/vishalwaka/MultiTags
Swift 3バージョン
UICollectionViewFlowLayoutサブクラスを作成してこのメソッドを貼り付けるだけです。
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let answer = super.layoutAttributesForElements(in: rect) else { return nil }
for i in 1..<answer.count {
let currentAttributes = answer[i]
let previousAttributes = answer[i - 1]
let maximumSpacing: CGFloat = 8
let Origin = previousAttributes.frame.maxX
if (Origin + maximumSpacing + currentAttributes.frame.size.width < self.collectionViewContentSize.width && currentAttributes.frame.Origin.x > previousAttributes.frame.Origin.x) {
var frame = currentAttributes.frame
frame.Origin.x = Origin + maximumSpacing
currentAttributes.frame = frame
}
}
return answer
}
InstagramのようにSwift 3
セル行間隔の私の解決策:
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.rgb(red: 227, green: 227, blue: 227)
cv.showsVerticalScrollIndicator = false
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 1
return cv
}()
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
switch UIDevice.current.modelName {
case "iPhone 4":
return CGSize(width: 106, height: 106)
case "iPhone 5":
return CGSize(width: 106, height: 106)
case "iPhone 6,7":
return CGSize(width: 124, height: 124)
case "iPhone Plus":
return CGSize(width: 137, height: 137)
default:
return CGSize(width: frame.width / 3, height: frame.width / 3)
}
}
デバイスをプログラム的に検出する方法: https://stackoverflow.com/a/26962452/6013170
以前のバージョンは実際にはセクション> 1では動作しませんでした。だから私の解決策はここで見つかりました https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/ 怠け者のために:
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributesForElementsInRect = super.layoutAttributesForElements(in: rect)
var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()
// use a value to keep track of left margin
var leftMargin: CGFloat = 0.0;
for attributes in attributesForElementsInRect! {
let refAttributes = attributes
// assign value if next row
if (refAttributes.frame.Origin.x == self.sectionInset.left) {
leftMargin = self.sectionInset.left
} else {
// set x position of attributes to current margin
var newLeftAlignedFrame = refAttributes.frame
newLeftAlignedFrame.Origin.x = leftMargin
refAttributes.frame = newLeftAlignedFrame
}
// calculate new value for current margin
leftMargin += refAttributes.frame.size.width + 10
newAttributesForElementsInRect.append(refAttributes)
}
return newAttributesForElementsInRect
}
私は受け入れられた答えに問題があるので、私はそれを更新しました、これは私のために働いています:
h
@interface MaxSpacingCollectionViewFlowLayout : UICollectionViewFlowLayout
@property (nonatomic,assign) CGFloat maxCellSpacing;
@end
m
@implementation MaxSpacingCollectionViewFlowLayout
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
if (attributes.count <= 0) return attributes;
CGFloat firstCellOriginX = ((UICollectionViewLayoutAttributes *)attributes[0]).frame.Origin.x;
for(int i = 1; i < attributes.count; i++) {
UICollectionViewLayoutAttributes *currentLayoutAttributes = attributes[i];
if (currentLayoutAttributes.frame.Origin.x == firstCellOriginX) { // The first cell of a new row
continue;
}
UICollectionViewLayoutAttributes *prevLayoutAttributes = attributes[i - 1];
CGFloat prevOriginMaxX = CGRectGetMaxX(prevLayoutAttributes.frame);
if ((currentLayoutAttributes.frame.Origin.x - prevOriginMaxX) > self.maxCellSpacing) {
CGRect frame = currentLayoutAttributes.frame;
frame.Origin.x = prevOriginMaxX + self.maxCellSpacing;
currentLayoutAttributes.frame = frame;
}
}
return attributes;
}
@end
ストーリーボードでCollectionViewを選択し、サイズインスペクタに移動して、セルと行の最小間隔を5に設定します。
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
//Provide Width and Height According to your need
let width = UIScreen.main.bounds.width / 4
let height = UIScreen.main.bounds.height / 10
layout.itemSize = CGSize(width: width, height: height)
//For Adjusting the cells spacing
layout.minimumInteritemSpacing = 5
layout.minimumLineSpacing = 5
return UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
}()
私は水平型のUICollectionView
とサブクラス化されたUICollectionViewFlowLayout
を持っています。コレクションビューには大きなセルがあり、一度に1行ずつ表示され、コレクションビューは画面の幅に合わせて表示されます。
私はiago849の答えを試してみましたが、うまくいきましたが、それから私は彼の答えさえ必要としていないことがわかりました。何らかの理由で、minimumInterItemSpacing
を設定しても何も起こりません。私のアイテム/セル間の間隔はminimumLineSpacing
で完全に制御できます。
なぜそれがこのように機能するのかわからないが、機能する。