UIScrollBarの色を変更する

UIScrollViewnの右についてるインジケータ(スクロールバー)の色を変える機会があったのでメモ。

ios12まで

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let verticalIndicator = scrollView.subviews.last as? UIImageView

    verticalIndicator?.backgroundColor = UIColor.red
}

ios13から

iOS13からダークモードが新規に追加されたため、iOS12までのモノと同じコードで実装した場合色味が若干変化してしまいます。

iOS 13 端末で UIScrollView の Indicator に画像を設定するコード部分がクラッシュしていたのでその対応という記事にやりたいことがほとんど詰まっていたのでコードをお借りして実装しました。

記事の中では画像だけ独自で設定しているようだったのですが、単色の画像を用意するというのも馬鹿馬鹿しいのでUIViewをUIImageに変更して設定しています。

extension PromotionDetailViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if let verticalScrollIndicator: UIView = scrollView.subviews.last {
            // 追加した画像があれば削除
            let subviews = verticalScrollIndicator.subviews
            for subview in subviews {
                subview.removeFromSuperview()
            }
            let scrollBarImageView = UIImageView.init(frame: .zero)
            scrollBarImageView.contentMode = .scaleToFill
            scrollBarImageView.image = createScrollBarImage()
            scrollBarImageView.translatesAutoresizingMaskIntoConstraints = false
            verticalScrollIndicator.addSubview(scrollBarImageView)
            // ScrollBar いっぱいに画像を設置
            scrollBarImageView.leadingAnchor.constraint(
                equalTo: verticalScrollIndicator.leadingAnchor,
                constant: 0.0
            ).isActive = true
            scrollBarImageView.bottomAnchor.constraint(
                equalTo: verticalScrollIndicator.bottomAnchor,
                constant: 0.0
            ).isActive = true
            scrollBarImageView.trailingAnchor.constraint(
                equalTo: verticalScrollIndicator.trailingAnchor,
                constant: 0.0
            ).isActive = true
            scrollBarImageView.topAnchor.constraint(
                equalTo: verticalScrollIndicator.topAnchor,
                constant: 0.0
            ).isActive = true
        }
    }

    private func createScrollBarImage() -> UIImage {
        //制約をつける際に引き延ばしてしまうのでサイズは適当
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
        view.backgroundColor = .red
        let renderer = UIGraphicsImageRenderer(bounds: view.bounds)
        return renderer.image { rendererContext in
            view.layer.render(in: rendererContext.cgContext)
        }
    }
}

参考文献

iOS 13 端末で UIScrollView の Indicator に画像を設定するコード部分がクラッシュしていたのでその対応

How to convert a UIView to an image