UICollectionViewのセル間隔


197

セクションのセル間隔を設定するにはどうすればよいUICollectionViewですか?私はminimumInteritemSpacingそれを5.0に設定したプロパティがあることを知っていますが、間隔は5.0に表示されません。フローアウトデリゲートメソッドを実装しました。

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{

    return 5.0;
}

それでも望ましい結果が得られません。最小間隔だと思います。最大間隔を設定する方法はありませんか?

シミュレーターsc


デリゲートメソッドに入っているかどうかを確認しましたか?ブレークポイントを置くことによって..
Prashant Nikam 2013年

はい、それはデリゲートに入ります、IBでも最小セル間隔を5に設定しました。ただし、最小スペースは、セル間の最小スペースが5であることを確認するために役立つプロパティだとは思わないが、コレクションビューに余分なスペースがある場合、その余分なスペースを使用します。最大セル間隔のようなものが必要です
Vishal Singh 2013

私は同じ問題を抱えています。5pxが機能しないようです。力強く私はUITableViewでこれを行うことができますが、UICollectionViewではできません...
jerik

いくつかの計算を行って修正しました。明日投稿します。:)
Vishal Singh

2016年のメモは簡単です: stackoverflow.com/a/28327193/294884
Fattie

回答:


145

トピックが古いことはわかっていますが、誰かがここで正しい答えを必要としている場合のために:

  1. 標準フローレイアウトを上書きします。
  2. そのような実装を追加します:

    - (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と完全に等しいことを保証します!!


それで、これをどこに置くのですか?
ジョニー

1
Jonnyさん、標準のフローレイアウトを継承し、このメソッドをコピーしてクラスに貼り付けてください。
iago849 14

1
mutableCopy:を作成する必要はありません。配列の内容を変更するのではなく、配列内のオブジェクトを変更します。
Brock Boland 14

5
私が何か間違ったことをしたり、このアイデアが100%機能しない場合があります。最後までスクロールすると、一部のセルが互いにオーバーレイしていることがわかります。(
pash3r

2
素晴らしいポスト。状況によっては、レイアウトの最終行のフォーマットを混乱させるエラーが発生しました。私が変更され解決するにはif:に、追加の条件 if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x) {
chrisoneiota

190

最初の質問をサポートします。私は間隔を5pxにしようとしましたUICollectionViewが、これも機能しません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;
}

更新:次のコードで問題を解決しました。

ここに画像の説明を入力してください

ViewController.m

#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

これははるかに良い答えです。UICollectionViewDelegateFlowLayoutで調整できるコールバックを見て、これがどのように調整できるかを確認できます。
cynistersix 2014

1
これを細くすることができるのは、アイテムの幅+間隔がuicollectionviewの幅と等しい場合のみです。
xi.lin 2015

@JayprakashDubey現在、私は迅速に対応していません。あなたはそれを試さなければなりません。幸運を祈る
jerik

5pxのセル間の幅をどこで指定していますか?
UKDataGeek 2017

1
主に1つのメソッドをオーバーライドするためにUICollectionViewLayoutをサブクラス化するのはやり過ぎのようであり、オーバーライドする必要のある他のすべてのメソッドを考えると簡単なことではないため、受け入れられたものよりはるかに良い答えです。
シンデセリア2017

80

水平フローレイアウトを使用して、セル間の間隔も10ポイントになりました。間隔を削除するには、ゼロminimumLineSpacingと同様に設定する必要がありましminimumInterItemSpacingた。

UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
flow.itemSize = CGSizeMake(cellWidth, cellHeight);
flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flow.minimumInteritemSpacing = 0;
flow.minimumLineSpacing = 0;

また、すべてのセルが同じサイズの場合、デリゲートメソッドを使用する代わりに、フローレイアウトにプロパティを直接設定する方が簡単で効率的です。


34
驚いたことに、minimumLineSpacingはセル間の水平方向のスペースに影響します。
マットH

4
私も、水平スクロールとセル間のゼロ間隔が必要です。minimumLineSpacing= 0がキーです。
Wingzero、2015

3
私はこの効果を得ることができたなしで使用しますminimumInteritemSpacingminimumLineSpacing = 0水平レイアウトを設定するだけで、アイテム間の水平間隔が削除されました。
Ziewvater、2015年

1
考えてみれば、アイテム間の水平距離は、水平に流れるレイアウトの行間です。行間隔は、典型的な垂直方向に流れるレイアウトのアイテム間の垂直距離です。
lancejabr 2017

62

これは最小の行間であり、アイテム間の最小の間隔やセルスペースではないことに注意してください。これは、collectionViewのスクロール方向がHORIZONTALだからです。

垂直の場合は、セル間の水平スペースにはセルスペースまたはアイテム間スペースを設定し、セル間の垂直スペースには行スペースを設定する必要があります。

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
}

0を返すと下部のスペースがなくなりました。右側のスペースを削除するには?
バンガロール

ねえ、私はあなたの質問をよく理解していませんでした。しかし、私はinsetForSectionAtIndexがあなたが探しているものだと思います。-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {return UIEdgeInsetsMake(5、10、5、10); }
Vincent Joy

水平と垂直の両方の最小行間です。
Swati

あなたは私の日を保存しました(Y)。
Umair_UAS

おお、私の言葉!信じられない。ありがとう
Magoo

36

次のコードを試して、各アイテムの間隔が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;
}

SOで適切に表示されるように、コードをコードブロックとしてフォーマットしてください。
コンジット

33

最も人気のある回答の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
    }
}

super.layoutAttributesForElements(in:rect)はnilを返しますか?
Ashok R

これを使用する他のすべてのメソッドと同様に、これは複数の行に対して適切に機能しません。適切なデリゲートメソッドとプロパティが0を使用するように設定されていても、断続的な丸めエラースタイルのギャップが行間に残ります。UICollectionViewのレンダリングの問題である可能性があります。
Womble

30

IBを使用してセルまたは行の間隔を設定する非常に簡単な方法を見つけました。

ストーリーボード/ XibファイルからUICollectionViewを選択し、下の画像で指定されているようにサイズインスペクターをクリックします。

ここに画像の説明を入力してください

プログラムでスペースを構成するには、次のプロパティを使用します。

1)行間のスペースを設定します。

[self.collectionView setMinimumLineSpacing:5];

2)アイテム/セル間のスペースを設定します。

[self.collectionView setMinimumInteritemSpacing:5];

1
つまり、指定された値よりも大きく、常に指定された値とは限りません。
Vishal Singh

21

プロパティ名minimumInterItemSpacingに注意してください。これは、正確な間隔ではなく、アイテム間の最小間隔になります。minimumInterItemSpacingをある値に設定すると、間隔がそれより小さい値にならないことが保証されます。しかし、より高い値を取得する可能性があります。

実際、アイテム間の間隔は、いくつかの要素itemSizesectionInsetに依存します。コレクションビューは、これらの値に基づいてコンテンツを動的に配置します。したがって、正確な間隔を保証することはできません。sectionInsetminimumInterItemSpacingで試行錯誤を行う必要があります。


1
@アニルエッジ昆虫?:D
NightFury 14年

10
sectionInsectsにバグがある可能性があります。
Nestor

24
昆虫==バグ&&昆虫!=インセット:)
Nestor

16

Swift 3.0、Xcode 8の回答

1.コレクションビューのデリゲートを設定していることを確認してください

class DashboardViewController: UIViewController {
    @IBOutlet weak var dashboardCollectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        dashboardCollectionView.delegate = self
    }
}

2.UICollectionViewDelegate ではなく、UICollectionViewDelegateFlowLayoutプロトコルを実装します。

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
    }
}

1
そこで公衆を削除できると思います。正常に動作し、他のすべての関数と一致している必要があります。
エドワードポッター、

これは垂直スクロールコレクションビューで機能しますか?iPhone 6sや6s Plusなどのデバイスで2つのセルを水平に表示するコレクションビューがありますが、5s、5、およびSEよりも低いものは1つのセルのみを表示する必要があります。私の現在のコードは機能していますが、6s Plusデバイスでは、セル間のギャップが大きすぎて醜く見えます。そのギャップを小さくしようとしていますが、他のすべてのデバイスが私の設計に従って機能しているため、これが唯一の要件です。
AnBisw 2017

11

スペーシングのための単純なコード

let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 10 // Some float value

3
水平方向のセル間隔については、minimumLineSpacingを使用する必要があります
Alfi

9

投票の回答(とも迅速なバージョン右に大きなスペースがあるだろう。小さな問題があります)。

これは、フローレイアウトがセル間隔を正確にするためにカスタマイズされており、フロートが左にあるためです。振る舞うためです。

私の解決策は、セクションはめ込みを操作することです。これにより、セクションは中央に揃えられますが、間隔は指定どおりです。

以下のスクリーンショットでは、アイテム/行の間隔は正確に8ポイントですが、セクションの左右のインセットは8ポイントより大きくなります(中央揃えにするため)。

等間隔のセル

そのようなSwiftコード:

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
}

1
'NSInvalidArgumentException'が発生しました、理由: '*** setObjectForKey:object cannot be nil(key:<NSIndexPath:0xc000000000000016> {length = 2、path = 0-0})'キャッチされない例外。
DaftWooly 2016年

:私は間違っていない場合は...、あなたのwhileループは同等です let n = Int((containerWidth + minItemSpacing)/((itemWidth+minItemSpacing)))
DaftWooly

コードをそのまま使用しませんでしたが、これは、コレクションビューのアウトフローレイアウトを実装するための最良のリファレンスを与えてくれました。歓声
Dima Gimburg 2017

8

定義する UICollectionViewDelegateFlowLayoutヘッダーファイルでプロトコルをます。

次のUICollectionViewDelegateFlowLayoutようなプロトコルのメソッドを実装します。

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(5, 5, 5, 5);
}

UIEdgeInsetMakeメソッドのアップルのドキュメントを表示するには、ここをクリックしてください。


3

実際のセルサイズを変更せずに間隔を調整したい場合、これが私にとって最も効果的な解決策です。#xcode 9#tvOS11#iOS11 #swift

したがって、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
}

3

ストーリーボードアプローチ

ストーリーボードでCollectionViewを選択し、サイズインスペクターに移動して、セルと行の最小間隔を5に設定します。

プログラムによるSwift 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)
    }()

2

私はモノタッチを使用しているので、名前とコードは少し異なりますが、コレクションビューの幅が(x *セル幅)+(x-1)* MinimumSpacingと等しいことを確認することでこれを行うことができますx =量行あたりのセル数。

MinimumInteritemSpacingとセルの幅に基づいて次の手順を実行するだけです

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;

2

私は水平UICollectionViewでサブクラス化されていますUICollectionViewFlowLayoutます。コレクションビューには大きなセルがあり、一度に1行しか表示されません。コレクションビューは画面の幅に合わせて表示されます。

私はiago849の答えを試してみましたが、うまくいきましたが、私は彼の答えさえ必要ないことを知りました。何らかの理由で、を設定しminimumInterItemSpacingても何も起こりません。アイテム/セル間の間隔は、minimumLineSpacing

なぜこのように動作するのかはわかりませんが、動作します。


1
これは本当のようです -奇妙なことに、 "lines"の値は、実際には、水平レイアウトの場合のアイテム間のセパレータです。
Fattie

@ user3344977さん、こんにちは。この問題を別の質問に分けて、水平スクロールコレクションビューに直接対処することで、一部の人が見つけやすくなることにしました。そこであなたの答えを参照します。私の質問は次のとおりです。stackoverflow.com
アンディウェインスタイン

1

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


それはいいね。しかし、同様のソリューションを要素間の垂直間隔に適用できるかどうか疑問に思っていました
p0lAris

水平スクロールがある場合の垂直間隔?
luk2302 2015

1

上記の溶液による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
   }
}

2
このアプローチを使用するSOの他の回答と同様に、これは、collectionViewの幅全体にセルを合わせるために機能しますが、断続的な可変高さのギャップが行間に残ります。これは、CollectionViewが実際にレンダリングする方法の制限である可能性があります。
Womble

1

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
}

これは水平方向のフィッティングで機能しますが、minimumLineSpacingForSectionAtが0を返し、layout.minimumLineSpacingが0に設定されていても、行間にギャップが残ります。また、最初のループがアウトになるため、collectionViewでタッチするとアプリがクラッシュします範囲の。
Womble

1

私は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


0

以前のバージョンはセクション> 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
}

0

受け入れられた回答に問題があるため、更新しました。これは私にとってはうまくいきます:

.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

0

Swift 3Instagramのようなセルライン間隔の私の解決策:

ここに画像の説明を入力してください

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


0

横向きのコレクションビューを作成する場合、セル間にスペースを空けるには、プロパティを設定する必要がありますminimumLineSpacing


-1

この方法で遊んでみてください:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                    layout:(UICollectionViewLayout*)collectionViewLayout
    insetForSectionAtIndex:(NSInteger)section {

    UIEdgeInsets insets = UIEdgeInsetsMake(?, ?, ?, ?);

    return insets;
}

2
これは、セルではなくセクション間の間隔でのみ機能します
Diego A. Rincon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.