質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.84%

  • Swift

    6327questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    3587questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

CollectionViewのカスタムレイアウトに等間隔のマージン(隙間)を作りたい。 [swift]

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 54

kou009

score 5

[やりたいこと]
・Cell間のマージンを等間隔(サイズは2)にしたい。

CollectionViewのカスタムレイアウトを実装しています。
こちらのサイトを参考に作成しました。

Cell間のマージン(隙間)のサイズを2にしたいです。(シミュレーターで表示されてるマージンはのサイズは、8です。)
シミュレーターでは、topのマージンがなくなっていますが、topのマージンも2にしたいです。
すべてのCell間(top,left,bottom,right全て)に等間隔のマージン(サイズは2)を作りたいです。

イメージ説明

CustomCollectionViewFlowLayoutクラスを、コレクションビューにアタッチしています。
コードはこちらのページのCustomCollectionViewFlowLayoutクラスのコードとほぼ同じです。 
イメージ説明

カスタムレイアウトのコードです。

import UIKit

class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {

    private static let kMaxRow = 3
    var maxColumn = kMaxRow

    private var sectionCells = [[CGRect]]()
    private var contentSize = CGSize.zero

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init() {
        super.init()
        self.sectionInset = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
        self.minimumLineSpacing = 2
        self.minimumInteritemSpacing = 2
        self.sectionInset = UIEdgeInsetsMake(2, 2, 2, 2)
    }

    override func prepare() {
        super.prepare()
        sectionCells = [[CGRect]]()

        if let collectionView = self.collectionView {
            contentSize = CGSize(width: collectionView.bounds.width - collectionView.contentInset.left - collectionView.contentInset.right, height: 0)
            let smallCellSideLength: CGFloat = (contentSize.width - super.sectionInset.left - super.sectionInset.right - (super.minimumInteritemSpacing * (CGFloat(maxColumn) - 1.0))) / CGFloat(maxColumn)

            for section in (0..<collectionView.numberOfSections) {
                var cells = [CGRect]()
                let numberOfCellsInSection = collectionView.numberOfItems(inSection: section)
                var height = contentSize.height

                var x:CGFloat = 0
                var y:CGFloat = 0
                var cellwidth:CGFloat = 0
                var cellheight:CGFloat = 0

                for i in (0..<numberOfCellsInSection) {
                    let position = i  % (numberOfCellsInSection)
                    let cellPosition = position % 6

                    switch cellPosition {
                    case 0:
                        if section % 2 == 0 {
                            x = super.sectionInset.left
                            y = contentSize.height + super.sectionInset.top
                            cellwidth = 2 * smallCellSideLength + super.minimumInteritemSpacing
                            cellheight = 2 * smallCellSideLength + super.minimumLineSpacing
                        }else{
                            x = super.sectionInset.left
                            y = contentSize.height + super.sectionInset.top
                            cellwidth = smallCellSideLength
                            cellheight = smallCellSideLength
                        }
                    case 1:
                        if section % 2 == 0 {
                            x = 2 * (smallCellSideLength + super.minimumInteritemSpacing) + super.sectionInset.left
                            y = 0 * (smallCellSideLength + super.minimumLineSpacing) + contentSize.height + super.sectionInset.top
                            cellwidth = smallCellSideLength; cellheight = smallCellSideLength
                        }else {
                            x = smallCellSideLength + super.minimumInteritemSpacing + super.sectionInset.left
                            y = (0 * (smallCellSideLength + super.minimumLineSpacing)) + contentSize.height + super.sectionInset.top
                            cellwidth = 2 * smallCellSideLength  + super.minimumInteritemSpacing
                            cellheight = 2 * smallCellSideLength + super.minimumLineSpacing
                        }
                    case 2:
                        if section % 2 == 0 {
                            x = 2 * (smallCellSideLength + super.minimumInteritemSpacing) + super.sectionInset.left
                            y = 1 * (smallCellSideLength + super.minimumLineSpacing) + contentSize.height + super.sectionInset.top
                            cellwidth = smallCellSideLength; cellheight = smallCellSideLength
                        }else{
                            x = super.sectionInset.left
                            y = (1 * (smallCellSideLength + super.minimumLineSpacing)) + contentSize.height + super.sectionInset.top
                            cellwidth = smallCellSideLength; cellheight = smallCellSideLength
                        }
                    case 3:
                        x = super.sectionInset.left
                        y = 2 * (smallCellSideLength + super.minimumLineSpacing) + contentSize.height + super.sectionInset.top
                        cellwidth = smallCellSideLength; cellheight = smallCellSideLength
                    case 4:
                        x = smallCellSideLength + super.minimumInteritemSpacing + super.sectionInset.left
                        y = 2 * (smallCellSideLength + super.minimumLineSpacing) + contentSize.height + super.sectionInset.top
                        cellwidth = smallCellSideLength; cellheight = smallCellSideLength
                    case 5:
                        x = 2 * (smallCellSideLength + super.minimumInteritemSpacing) + super.sectionInset.left
                        y = 2 * (smallCellSideLength + super.minimumLineSpacing) + contentSize.height + super.sectionInset.top
                        cellwidth = smallCellSideLength; cellheight = smallCellSideLength
                    default:
                        x = 0; y = 0
                        cellwidth = 0; cellheight = 0
                        break
                    }

                    let cellRect = CGRect(x: x, y: y, width: cellwidth, height: cellheight)
                    cells.append(cellRect)

                    if (height < cellRect.origin.y + cellRect.height) {
                        height = cellRect.origin.y + cellRect.height
                    }
                }
                contentSize = CGSize(width: contentSize.width, height: height)
                sectionCells.append(cells)
            }
        }
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        var layoutAttributes = [UICollectionViewLayoutAttributes]()

        if let collectionView = self.collectionView {
            for i in 0..<collectionView.numberOfSections {
                let numberOfCellsInSection = collectionView.numberOfItems(inSection: i);
                for j in 0..<numberOfCellsInSection {

                    let indexPath = IndexPath(row: j, section: i)
                    if let attributes = layoutAttributesForItem(at: indexPath) {
                        if (rect.intersects(attributes.frame)) {
                            layoutAttributes.append(attributes)
                        }
                    }
                }
            }
        }
        return layoutAttributes
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let attributes = super.layoutAttributesForItem(at: indexPath)
        attributes?.frame = sectionCells[indexPath.section][indexPath.row]
        return attributes
    }

    override var collectionViewContentSize : CGSize {
        return contentSize
    }
}

CollectionViewを保持しているクラスです。

import UIKit
import SDWebImage

class DiscoverViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    @IBOutlet weak var myCollectionView: UICollectionView!

    var posts: [Post] = []



    override func viewDidLoad() {
        super.viewDidLoad()


        myCollectionView.delegate = self
        myCollectionView.dataSource = self


        loadTopPosts()
    }

    func loadTopPosts() {
        Api.Post.observeTopPosts(page: page) { (post) in
            self.posts.append(post)
            self.myCollectionView.reloadData()
        }
    }



    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return section<posts.count/6 ? 6 : posts.count%6
    }
    //セクションの総数を返す
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return (posts.count-1)/6+1
    }
    //Cellに値を設定する
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CustomCollectionViewCell


        let photoUrlString = self.posts[indexPath.section * 6 + indexPath.row].imageUrls[0]
        let photoUrl = URL(string: photoUrlString)
        cell.imageView1.sd_setImage(with: photoUrl)

        return cell
    }


}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

CollectionViewには疎いですが、
参考にしたページを見させていただきました。

その通り、コードをコピーして、走らせ、
改変して見て様子を見ました。

        self.sectionInset = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
        self.minimumLineSpacing = 2
        self.minimumInteritemSpacing = 2
        self.sectionInset = UIEdgeInsetsMake(2, 2, 2, 2)

で、わかったことですが、
上記の1行目と4行目で同じことを別の方法で定義してるように見えます。
どちらかをコメントアウトしても、表示は何も変わらなかったです。
なので、どちらか一方で定義すれば良さそうです。
そして、それが定義しているものはセクション全体の周囲の空白です。

イメージ説明

これがself.sectionInsetを30に設定した時です。

self.minimumLineSpacing を80に設定を変えてみたら、
下記のような表示になりました。

イメージ説明

同様にself.minimumInteritemSpacing を80に変えたら
今度は下記のようになりました。

イメージ説明

最後にkou009さんの実現したいことですが、
自分は全てを2に設定したら、全ての間隔が2に設定され、
そのまま狭い間隔でした。
シュミレーターだけでなく、実機で試して見ましたか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/31 17:40

    CustomCollectionViewFlowLayoutのコードが間違ってると思いこんでいましたが、
    hamejiさんが等間隔で表示できたとのことですので、
    コードはそのままで他のやり方を試してみました。
    そしたら、すべての間隔を2で表示させることができました。

    以前のやり方は、storyboardから、collectionViewに直接CustomCollectionViewFlowLayoutをアタッチしていましたが、
    アタッチせずに、動的にレイアウトを生成(myCollectionView.collectionViewLayout = CustomCollectionViewFlowLayout())したら、サイズ2で等間隔でレイアウトを作ることができました。
    丁寧にご回答いただきありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Swift

    6327questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    3587questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。