2021年7月5日月曜日

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

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

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

Viewの構成

Viewの構成は、UIScrollViewの中にコンテンツ用のUIViewを入れるのみです。
    private let scrollView = UIScrollView()
    private let contentView = UIView()


    private func setupViews() {
        scrollView.addSubview(contentView)
        addSubview(scrollView)
    }

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

    func setup(_ view: UIView) {
        contentView.addSubview(view)
        view.snp.makeConstraints {
            $0.edges.equalTo(contentView)
        }
    }



制約をセットする

scrollViewの制約は、通常通り親Viewに対して同じ大きさになるよう制約をセットします。
contentViewの制約は工夫が必要で、親Viewに対して横Centerの指定とleftに対してgreaterThanOrEqualToを指定します。
この2つの制約によりCenter表示が可能になります。
    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が発生したため、次の制約を追加します。
$0.left.equalTo(scrollView.contentLayoutGuide).priority(.low)



完成形のコード

上記の全てを組み合わせると、次のようなコードになります。
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)
        }
    }
}

0 件のコメント:

コメントを投稿