본문 바로가기
Project/PhotoDiary

🎶 이미지 테두리에 만드는 방법

by 밤새는 탐험가89 2025. 6. 25.
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