clyne의 개발 기록

[Swift] UIAlertController에 이미지 넣기 (커스텀) 본문

iOS/Swift

[Swift] UIAlertController에 이미지 넣기 (커스텀)

clyne_dev 2021. 5. 5. 22:27

안녕하세요!!!

오늘도 어김없이 돌아온 iOS 개발자 CNOO입니다!!

 

오늘 여러분께 소개해 드릴 것은 바로바로~~~~~~~~~

 

UIAlertViewController에  이미지 넣기 입니다!

선택지에도 넣고, 타이틀 쪽에도 넣고~~ 하는 방법입니당

 

먼저, 구현된 결과물 부터 보고 시작하도록 하겠습니다.

아래 Alert은 렛터디 내 1:1 쪽지함에서 구현한 Alert의 일부입니다.


제목 위에 Check모양의 이미지뷰가 들어있습니다. (alert 스타일)

 

 


제목 위에도 이미지가 들어있고, 보기에도 각각 이미지가 들어있네요 ( Sheet 스타일 )

 

요것을 구현해보도록 하겠습니다 ㅎㅎ

 

 


1. UIAlertController를 상속받는  MyAlertController 생성

저는 여기서 렛터디의 앞글자를 따서 LTAlertController라고 칭했습니다. 원하시는 것으로 클래스를 생성하시면 됩니다.


class LTAlertController: UIAlertController {
    private(set) var originalTitle: String?
    private var spaceAdjustedTitle: String = ""
    private weak var imageView: UIImageView? = nil
    private var previousImgViewSize: CGSize = .zero
    
    override var title: String? {
        didSet {
            if title != spaceAdjustedTitle {
                originalTitle = title
            }
        }
    }
    
    func setTitleImage(_ image: UIImage?, tintColor: UIColor? = nil) {
        guard let imageView = self.imageView else {
            let imageView = UIImageView(image: image)
            if let color = tintColor {
                imageView.tintColor = color
            }
            self.view.addSubview(imageView)
            self.imageView = imageView
            return
        }
        imageView.image = image
    }
  
    
    // MARK: -  Layout
    override func viewDidLayoutSubviews() {
        guard let imageView = imageView else {
            super.viewDidLayoutSubviews()
            return
        }
        // 이미지 사이즈가 변경되면, 제목도 그에 맞게 조정
        if previousImgViewSize != imageView.bounds.size {
            previousImgViewSize = imageView.bounds.size
            adjustTitle(for: imageView)
        }
        // 이미지뷰를 위치시킵니다. (각자 원하는 크기와 위치의 값을 넣어주세요)
        let linesCount = newLinesCount(for: imageView)
        let padding = Constants.padding(for: preferredStyle)
        imageView.center.x = view.bounds.width / 2.0
        imageView.center.y = padding + linesCount * lineHeight / 2.0
        imageView.frame.size = CGSize(width: 50, height: 50)
        super.viewDidLayoutSubviews()
    }
    
    // 이미지뷰와 제목의 위치를 맞추기 위함
    private func adjustTitle(for imageView: UIImageView) {
        let linesCount = Int(newLinesCount(for: imageView))
        let lines = (0..<linesCount).map({ _ in "\n" }).reduce("", +)
        spaceAdjustedTitle = lines + (originalTitle ?? "")
        title = spaceAdjustedTitle
    }
    
    private func newLinesCount(for imageView: UIImageView) -> CGFloat {
        return ceil(imageView.bounds.height / lineHeight)
    }
    
    private lazy var lineHeight: CGFloat = {
        let style: UIFont.TextStyle = self.preferredStyle == .alert ? .headline : .callout
        return UIFont.preferredFont(forTextStyle: style).pointSize
    }()
    
    struct Constants {
        static var paddingAlert: CGFloat = 22
        static var paddingSheet: CGFloat = 11
        static func padding(for style: UIAlertController.Style) -> CGFloat {
            return style == .alert ? Constants.paddingAlert : Constants.paddingSheet
        }
    }
}

extension UIAlertAction {
    
    // 버튼 왼쪽에 이미지를 넣기 위함.
    var actionImage: UIImage? {
        get {
            if self.responds(to: Selector(Constants.imageKey)) {
                return self.value(forKey: Constants.imageKey) as? UIImage
            }
            return nil
        }
        set {
            if self.responds(to: Selector(Constants.imageKey)) {
                self.setValue(newValue, forKey: Constants.imageKey)
            }
        }
    }
    
    private struct Constants {
        static var imageKey = "image"
    }
}

 


 

위와같이  LTAlertController를 생성한 뒤에, 아래와 같이 적용하면 됩니다!!

 

 

 


2. 적용하기

위에서 작성한 LTAlertController를 이용해 얼럿을 띄우는 코드를 작성해보도록 하겠습니다.

 


 

DispatchQueue.main.async {

    let alert = AlertController(title: "제목", message: nil, preferredStyle: .alert)
    alert.setTitleImage(UIImage(systemName: "checkmark.circle")!)
    alert.addAction(UIAlertAction(title: "취소", style: .default, handler: { _ in
        print("취소 동작")
    }))
    alert.addAction(UIAlertAction(title: "확인", style: .default, handler: { _ in
        print("확인 동작")
    }))
    
    self.present(alert, animated: true, completion: nil)
    
}

이러면 맨 위에있는 첫번쨰 예시와 동일한 모양의 얼럿이 나오게 됩니다!

 

버튼에도 이미지를 넣고싶으시다면?!

아까 위에서 구현했던 UIAlertController의 확장변수에 이미지를 넣어주시면 되곘죠?


let actionWithImage = UIAlertAction(title: "이미지버튼", style: .default, handler: { _ in
        print("이미지버튼 동작")
    })
actionWithImage.actionImage = UIImage(systemName: "trash")?.withTintColor(.blue)

 

 

 

 

자, 이제 UIAlertController에 이미지를 넣을 수 있게 되었습니다 짝짝짝~~

 

도움이 되셨나요?

궁금한 점은 댓글 달아주세요!! :)