본문 바로가기

TIL

[TIL] Resizable Image 만드는 법

요즘 채팅 기능을 구현하던 와중 이미지 크기를 부분적으로 조절하여 말풍선을 만들 수 있다는 사실을 구글링 중 알게 되어 오늘은 이 구현 과정에 대해 포스팅해보고자 합니다.

 

Stretchable Image

애플 공식 문서에 따르면 Stretchable Image라는 개념이 나옵니다.

공식 문서에 따르면 여기서 각 inset에 0이 아닌 값이 주어지면 아래 그림들과 마찬가지로 이미지를 9등분된다고 합니다.

 

이 9등분된 영역은 각각 다른 특색을 가지고 있는데요.

예를 들어, Top/Bottom Inset 영역은 높이가 고정되고, 너비가 늘어납니다.

반면에 Left/Right Inset 영역은 너비가 고정되고, 높이가 늘어납니다.

그리고 나머지 코너 영역들은 너비와 높이가 고정됩니다.

위 그림은 이미지가 Stretch되는 영역을 나타냅니다.

 

Stretchable Image 구현

공식 문서에 따르면 Stretchable Image 구현은 resizableImage(withCapInsets:) 메서드resizableImage(withCapInsets:resizingMode:) 메서드를 이용하여 기존 이미지에 Inset를 추가하면 구현할 수 있다고 합니다.

 

저는 여기서 resizableImage(withCapInsets:resizingMode:) 메서드를 활용해보겠습니다.

 

우선 아래 코드처럼 Stretchable Image를 정의한 커스텀 UIImageView를 정의해줍니다.

아래 코드를 간단히 설명드리자면 기존 말풍선 원본 이미지 크기의 40%로 Inset을 잡아주었습니다.

이렇게 Inset을 비율로 잡아준 이유는 말풍선 이미지 파일 해상도를 1x, 2x, 3x 해상도의 이미지별로 모두 활용하기 때문입니다.

final class ChatBubbleImageView: UIImageView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        
        configureUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func configureUI() {
        let image = UIImage(named: "messageBubble")
        // 기존 말풍선 원본 이미지 크기의 40%로 Inset 설정
        let horizontalInset = (image?.size.width ?? 0.0) * 0.4
        let verticalInset = (image?.size.height ?? 0.0) * 0.4
        self.image = image?.resizableImage(
            withCapInsets: UIEdgeInsets(
                top: verticalInset,
                left: horizontalInset,
                bottom: verticalInset,
                right: horizontalInset),
            resizingMode: .stretch
        ).withRenderingMode(.alwaysTemplate)
    }
}

 

아래 코드처럼 위에서 정의된 커스텀 ImageView를 화면에 보여줄 ViewController에 정의하고 그 내부에 메세지 내용을 보여줄 UILabel을 정의해준 뒤 커스텀한 ImageView 하위 계층으로 추가해주어 그 내부에서 말풍선 이미지에 대한 일정한 padding을 잡아주었습니다.

import UIKit
import SnapKit

final class ViewController: UIViewController {
    
    private let chatBubbleImageView: ChatBubbleImageView = {
        let bubbleImageView = ChatBubbleImageView(frame: .zero)
        bubbleImageView.tintColor = .systemGray3
        return bubbleImageView
    }()
    
    private let msgLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.text = "안녕하세요안녕하세요안녕하세요안녕하세요안녕하세요"
        return label
    }()
    
    private let contentPadding: CGFloat = 8
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureConstraints()
    }
    
    private func configureConstraints() {
        view.addSubview(chatBubbleImageView)
        
        chatBubbleImageView.addSubview(msgLabel)
        
        chatBubbleImageView.snp.makeConstraints {
            $0.top.leading.equalTo(view.safeAreaLayoutGuide).offset(16.0)
            $0.trailing.lessThanOrEqualTo(view.safeAreaLayoutGuide).inset(16.0)
        }
        
        msgLabel.snp.makeConstraints {
            $0.edges.equalToSuperview().inset(contentPadding)
        }
    }
    
}

 

그러면 아래 사진처럼 말풍선이 UILabel의 내용에 따라 크기가 동적으로 변하는 것을 확인해보실 수 있습니다.

 

이상 Stretchable Image를 이용해 말풍선을 구현해 보았습니다.

처음보는 개념이었지만 생각보다 구현은 어렵지 않았던 것 같습니다.

끝까지 읽어주셔서 감사합니다.

 

참고 사이트

https://developer.apple.com/documentation/uikit/uiimage/#1658362 (애플 공식 문서 - Define a Stretchable Image)

https://developer.apple.com/documentation/uikit/uiimage/1624127-resizableimage (애플 공식 문서 - resizableImage(withCapInsets:resizingMode:))

https://applecider2020.tistory.com/76 (채팅 말풍선 구현 참고)