728x90
SMALL
✅ 구현 내용
이미지 스티커를 보여주는 커스텀 UIView로, 선택되었을 때 파란색 점선 테두리와 삭제 버튼이 나타나도록 한다.
이는 UI 디자인 툴이나 사진 편집 앱에서 자주 쓰이는 구성입니다.
✅ 전체 코드
class StickerContainerView: UIView {
// MARK: - UI Components
let imageView: UIImageView
private let borderLayer = CAShapeLayer()
private let deleteButton = UIButton(type: .custom)
// MARK: - Init
init(image: UIImage) {
self.imageView = UIImageView(image: image)
super.init(frame: CGRect(origin: .zero, size: CGSize(width: 150, height: 150)))
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Function
private func setupUI() {
self.backgroundColor = .clear
self.addSubview(imageView)
imageView.frame = self.bounds
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
imageView.contentMode = .scaleAspectFit
imageView.isUserInteractionEnabled = false
// 점선 테두리
borderLayer.strokeColor = UIColor.systemRed.cgColor
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.lineDashPattern = [4, 4]
borderLayer.lineWidth = 2.5
layer.addSublayer(borderLayer)
// 삭제 버튼
deleteButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal)
deleteButton.tintColor = .systemBackground
//deleteButton.backgroundColor = .systemBackground
deleteButton.frame = CGRect(x: self.bounds.width - 20, y: -20, width: 40, height: 40)
deleteButton.addTarget(self, action: #selector(deleteTapped), for: .touchUpInside)
deleteButton.autoresizingMask = [.flexibleLeftMargin, .flexibleBottomMargin]
self.addSubview(deleteButton)
}
override func layoutSubviews() {
super.layoutSubviews()
borderLayer.path = UIBezierPath(rect: self.bounds).cgPath
}
@objc private func deleteTapped() {
self.removeFromSuperview()
}
func setSelected(_ isSelected: Bool) {
borderLayer.isHidden = !isSelected
deleteButton.isHidden = !isSelected
}
}
let imageView: UIImageView
private let borderLayer = CAShapeLayer()
private let deleteButton = UIButton(type: .custom)
- imageView: 이미지를 표시하는 뷰.
- borderLayer: 외곽 테두리를 나타내는 CAShapeLayer (Core Animation 레이어).
- deleteButton: 삭제 버튼.
init(image: UIImage) {
self.imageView = UIImageView(image: image)
super.init(frame: CGRect(origin: .zero, size: CGSize(width: 150, height: 150)))
setup()
}
- 초기화 시 이미지 하나를 받아 UIImageView로 설정.
- 기본 사이즈는 150x150으로 지정.
- setup() 메서드를 호출해서 뷰의 구성 요소를 셋업함.
borderLayer.strokeColor = UIColor.systemRed.cgColor
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.lineDashPattern = [4, 4]
borderLayer.lineWidth = 2.5
layer.addSublayer(borderLayer)
- 빨간색 점선 테두리.
- CAShapeLayer를 이용해 성능 좋고 유연한 테두리를 그림.
- lineDashPattern: [4, 4] → 4pt 선, 4pt 공백 반복.
- layoutSubviews()에서 테두리 path 설정.
override func layoutSubviews() {
super.layoutSubviews()
borderLayer.path = UIBezierPath(rect: self.bounds).cgPath
}
- 뷰의 크기가 바뀔 때마다 테두리 경로를 다시 그림.
- 뷰의 전체 영역에 맞춰서 테두리를 그림.
@objc private func deleteTapped() {
self.removeFromSuperview()
}
- 삭제 버튼을 누르면 뷰 자체를 슈퍼뷰에서 제거함.
func setSelected(_ isSelected: Bool) {
borderLayer.isHidden = !isSelected
deleteButton.isHidden = !isSelected
}
- 선택되었을 때(isSelected == true)만 테두리와 삭제 버튼이 보이도록.
- 선택 상태 UI만 처리하고, 제스처는 외부에서 붙이도록 설계돼 있음.

728x90
LIST