✍️

UIImageViewを利用する上で理解しなければならないclipsToBounds

2022/09/11に公開

clipsToBoundsの重要性について理解しないでいると、UIImageViewに画像を貼り付ける上で意図した通りにならずに、おそらく頭を抱えることになると思います。私は頭を抱えましたので、忘れないうちに書き残しておきます。

clipsToBounds

https://developer.apple.com/documentation/uikit/uiview/1622415-clipstobounds

overviewの説明にもある通りサブビューを(その載っている)ビューのboundsの範囲内に閉じ込めるかどうかを決めるものです。これはUIViewのインスタンスプロパティとなっているので、たとえば継承しているUIImageViewも当てはまります。

これは、絵画で例えるとわかりやすいかと思います。UIKitで画像を載せようとすれば、おそらくUIImageViewを使う形になります。このUIImageViewは絵画で言えば、いわば額縁、フレームにあたります。そしてUIImageが当てはめられる絵画です。

絵画は必ずしも額縁に収まるとは限りません。その絵画に合わせた額縁を探すか、あるいは逆に絵画を額縁に合わせる必要があります。飾れるスペースというのはたいていは限られているので、ある程度フレームに合わせて絵を探すことになるでしょう。iOSアプリにおいても同様で、スペースはiPhoneなどのディスプレイであり、その画面に表示する画像というのは必然的に大きさが限られ、イメージをその枠内に収めなければなりません。

それを実現する上で重要なプロパティがclipsToBoundsです。
clips(切り取る) to(に対して)  bounds(バウンド、境界)であるので、枠に沿って切り取るという意味になるのではないかと思います。boundsはframeとの関係性があるので、もしかしたら意味の取り方は正しくないかもしれませんが、Swiftらしい英語で意味を読み取れる名前のプロパティに思えます。

実際に、どういう状態になるのか確認してみましょう。

clipsToBounds効いていない状態

clipsToBoundが働いていない状態は次のようなものです。

白い枠線はUIImageViewです。画像がはみ出してしまっているのがわかります。

clipsToBounds効いている状態

白い枠線のうちのみで画像が表示されるようになっており、Boundary(境界線上)にClip、切り取られているのがわかります。

実際のコード

この表示の設定を行なっているコードは次です。

 func setup() {
	//コードでレイアウト組む上で必要な操作
        imageView.translatesAutoresizingMaskIntoConstraints = false
	
	//アスペクト比を保ったままサイズは無視してViewのBoundsに収める
	//(つまり画像がはみ出すことは気にしない比)
	imageView.contentMode = .scaleAspectFill

        //画像を枠内に収めて、はみ出した部分はClip
	imageView.clipsToBounds = true

	//layerの設定
        imageView.layer.cornerRadius = 10
        imageView.layer.borderColor = UIColor.white.cgColor
        imageView.layer.borderWidth = 1
        imageView.layer.shadowColor = UIColor.lightGray.cgColor
        imageView.layer.shadowOffset = .init(width: 0, height: 5)
        imageView.layer.shadowOpacity = 0.5

        addSubview(imageView)
	
	//コードレイアウト
        NSLayoutConstraint.activate([
            imageView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.8),
            imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1.0),
            imageView.topAnchor.constraint(equalTo: topAnchor),
            imageView.leadingAnchor.constraint(equalTo: leadingAnchor),
            imageView.trailingAnchor.constraint(equalTo: leadingAnchor),
            imageView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
    } 

ちなみに、画像のアスペクト比の設定を、たとえば、.scaleAspectFitとすれば、アスペクト比を保ったまま、枠内に画像が収まる(Fit)しますが、アスペクト比を保ったままであるので不恰好な空白が生まれます。もし空白もなく全てを表示したいという場合には、UIImageViewの方が画像のアスペクト比やサイズに合わせてサイズを変える必要がありそうです。

アスペクト比は保ってあるものの、横に長いため、縦に空白ができてしまっているのがわかります。

まとめ

基本的なところですが、この辺り抜け落ちているとレイアウト組む時に頓珍漢なことをしでかしかねない、というかするので理解しておきましょう。

参考

https://qiita.com/Saayaman/items/a23519ff5a8ad287cf20

Discussion