Swift,Objective-Cプログラミング ~ iOS ~

Objective-C,Swift,Apple Watchなどのプログラミング

複数のViewを横並びにしていて、表示しきれない場合に折り返す表示を作る

はじめに

基本的には横並びにViewを並べたい。でも、iPhoneSEなどの横幅が小さい端末では表示しきれないので、その場合に折り返して、表示しきれなかったViewを表示したい。

たとえば、下記画像のような検索条件設定画面があるとします。

f:id:fjswkun:20200710150810p:plain

これはiPhone11の画像です。 検索条件で検索する商品のカテゴリを選択でき、選択したカテゴリが青色で表示されるとします。カテゴリ名が長いものがあったり、端末サイズが小さいものであった場合、表示しきれません。

端末サイズがiPhoneSEの場合は下記の画像のよう表示となります。

f:id:fjswkun:20200710160343p:plain

表示しきれない場合にフォントを小さくしたり、表示しきれない部分を...とするなどの方法はありますが、表示しきれない場合は折り返して表示するような実装を考えました。

結果として以下のようにします。

iPhone11の場合 f:id:fjswkun:20200710161016p:plain

iPhoneSEの場合 f:id:fjswkun:20200710161029p:plain

実装方法

表示しきれない場合に折り返して表示することはUICollectionViewで実現できます。ただし折り返してセルが表示される場合、セルの表示位置やセル間のスペースが期待通りにならないため、UICollectionViewFlowLayoutのサブクラスを作成し、実装する必要があります。

実装したUICollectionViewFlowLayoutは下記のとおりです。

import UIKit

class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
    let cellSpacing: CGFloat = 28
 
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        self.minimumLineSpacing = 5
        self.sectionInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
        let attributes = super.layoutAttributesForElements(in: rect)
        
        
        var leftMargin = sectionInset.left
        var maxY: CGFloat = 0
        attributes?.forEach { layoutAttribute in
            if layoutAttribute.frame.origin.y >= maxY {
                leftMargin = sectionInset.left
            }
            layoutAttribute.frame.origin.x = leftMargin
            leftMargin += layoutAttribute.frame.width + cellSpacing
            maxY = max(layoutAttribute.frame.maxY, maxY)
        }
        return attributes
    }
}

これをcollectionViewのcollectionViewLayoutプロパティに設定すればよい。

実装したサンプルはこちらにアップしています。 https://github.com/fuji2013/SampleNewlineView github.com