요즘 채팅 기능을 구현하던 와중 이미지 크기를 부분적으로 조절하여 말풍선을 만들 수 있다는 사실을 구글링 중 알게 되어 오늘은 이 구현 과정에 대해 포스팅해보고자 합니다.
Stretchable Image
애플 공식 문서에 따르면 Stretchable Image라는 개념이 나옵니다.
공식 문서에 따르면 여기서 각 inset에 0이 아닌 값이 주어지면 아래 그림들과 마찬가지로 이미지를 9등분된다고 합니다.
이 9등분된 영역은 각각 다른 특색을 가지고 있는데요.
예를 들어, Top/Bottom Inset 영역은 높이가 고정되고, 너비가 늘어납니다.
반면에 Left/Right Inset 영역은 너비가 고정되고, 높이가 늘어납니다.
그리고 나머지 코너 영역들은 너비와 높이가 고정됩니다.
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 (채팅 말풍선 구현 참고)
'TIL' 카테고리의 다른 글
[TIL] MVI 패턴 (0) | 2024.06.04 |
---|---|
[TIL] Realm-Swift 라이브러리 SPM Build 오류 대응(Privacy Manifest) (0) | 2024.05.19 |
[TIL] Pinterest UI 구현 (0) | 2024.05.15 |
[TIL] @propertyWrapper를 활용한 UserDefaults 리팩토링 (0) | 2024.05.14 |
[TIL] Socket 통신 구현 (0) | 2024.05.12 |