トラッキング コード

7/05/2021

画面幅より短い場合はCenterさせるUIScrollViewを作成する

次のようなViewを条件を満たすViewを作りたくなったので実装してみました。
  • 画面幅より短い場合は、Center表示させる
  • 画面幅より長い場合は、左寄せで表示し横スクロール可能である

完成イメージは次のような感じです。

Viewの構成

Viewの構成は、UIScrollViewの中にコンテンツ用のUIViewを入れるのみです。
1
2
3
4
5
6
7
8
private let scrollView = UIScrollView()
private let contentView = UIView()
 
 
private func setupViews() {
    scrollView.addSubview(contentView)
    addSubview(scrollView)
}

実際に表示させたいViewは、次のようにfunc setup(_)メソッドを使って挿入させることを想定しています。

1
2
3
4
5
6
func setup(_ view: UIView) {
    contentView.addSubview(view)
    view.snp.makeConstraints {
        $0.edges.equalTo(contentView)
    }
}



制約をセットする

scrollViewの制約は、通常通り親Viewに対して同じ大きさになるよう制約をセットします。
contentViewの制約は工夫が必要で、親Viewに対して横Centerの指定とleftに対してgreaterThanOrEqualToを指定します。
この2つの制約によりCenter表示が可能になります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private func setupConstraint() {
    scrollView.snp.makeConstraints {
        $0.edges.equalToSuperview()
    }
    contentView.snp.makeConstraints {
        $0.height.equalTo(scrollView.frameLayoutGuide)
        // 横幅より小さい場合は、Center
        // 横幅より大きい場合は、通常の左寄せ + スクロール
        $0.top.right.bottom.equalTo(scrollView.contentLayoutGuide)
        $0.left.equalTo(scrollView.contentLayoutGuide).priority(.low)
        $0.left.greaterThanOrEqualTo(scrollView.contentLayoutGuide)
        $0.centerX.greaterThanOrEqualToSuperview()
    }
}


ScrollのContent領域が定まらないというLayoutのwarningが発生したため、次の制約を追加します。
1
$0.left.equalTo(scrollView.contentLayoutGuide).priority(.low)



完成形のコード

上記の全てを組み合わせると、次のようなコードになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
final class HorizontalScrollView: UIView {
    private let scrollView = UIScrollView()
    private let contentView = UIView()
 
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
        setupConstraint()
    }
 
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupViews()
        setupConstraint()
    }
 
    private func setupViews() {
        scrollView.addSubview(contentView)
        addSubview(scrollView)
    }
 
    private func setupConstraint() {
        scrollView.snp.makeConstraints {
            $0.edges.equalToSuperview()
        }
        contentView.snp.makeConstraints {
            $0.height.equalTo(scrollView.frameLayoutGuide)
            // aligin center when content width < frame width
            // aligin left when content width > frame width
            $0.top.right.bottom.equalTo(scrollView.contentLayoutGuide)
            $0.left.equalTo(scrollView.contentLayoutGuide).priority(.low)
            $0.left.greaterThanOrEqualTo(scrollView.contentLayoutGuide)
            $0.centerX.greaterThanOrEqualToSuperview()
        }
    }
 
    func setup(_ view: UIView) {
        contentView.addSubview(view)
        view.snp.makeConstraints {
            $0.edges.equalTo(contentView)
        }
    }
}