관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 말풍선 뷰 구현 방법 (TooltipView, TipView, BalloonView, SpeechBubbleView), CAShapeLayer 본문

iOS 응용 (swift)

[iOS - swift] 말풍선 뷰 구현 방법 (TooltipView, TipView, BalloonView, SpeechBubbleView), CAShapeLayer

jake-kim 2022. 2. 16. 01:34

상단에 tip이 있는 tooltipView 

TooltipView 구현 아이디어

  • UIView를 상속받은 뷰에 UILabel 하나를 가지고 있고 해당 뷰에다가 CAShapeLayer를 이용하여 위에 삼각형 형태의 tip 적용
    * CAShapeLayer개념은 선 그리기(UIBezierPath, CAShapeLayer) 포스팅 글 참고
  • 구현된 TooltipView는 내부 UILabel의 크기에 따라서 view의 height값이 동적으로 조절되고, 파라미터로 상단 tip의 시작 x위치를 넘길 수 있어서 상단에 tip이 있는 확장성 있는 뷰로 구현

TooltipView 구현

  • (UI 레이아웃 구현에 편리를 위해 SnapKit 사용)
  • UIView를 상속받은 커스텀 뷰 생성
    import UIKit
    import SnapKit
    
    class MyTopTipView: UIView {
    }
  • init에서 삼각형모양의 tip 구현
    init(
      viewColor: UIColor,
      tipStartX: CGFloat,
      tipWidth: CGFloat,
      tipHeight: CGFloat
    ) {
      super.init(frame: .zero)
      self.backgroundColor = viewColor
      
      let path = CGMutablePath()
    
      let tipWidthCenter = tipWidth / 2.0
      let endXWidth = tipStartX + tipWidth
      
      path.move(to: CGPoint(x: tipStartX, y: 0))
      path.addLine(to: CGPoint(x: tipStartX + tipWidthCenter, y: -tipHeight))
      path.addLine(to: CGPoint(x: endXWidth, y: 0))
      path.addLine(to: CGPoint(x: 0, y: 0))
    
      let shape = CAShapeLayer()
      shape.path = path
      shape.fillColor = viewColor.cgColor
    
      self.layer.insertSublayer(shape, at: 0)
      self.layer.masksToBounds = false
      self.layer.cornerRadius = 16  
    }​
  • init안에서 UILabel을 추가하는 함수 구현
    • UILabel의 크기에 따라 뷰의 height값이 결정
      init(
        viewColor: UIColor,
        tipStartX: CGFloat,
        tipWidth: CGFloat,
        tipHeight: CGFloat
      ) {
        ...
        
        self.addLabel()
      }
      
      private func addLabel() {
        let titleLabel = UILabel()
        titleLabel.textColor = .white
        titleLabel.text = "iOS 앱 개발 알아가기, jake블로그, tipView 포스팅 글"
        titleLabel.numberOfLines = 0
        titleLabel.lineBreakMode = .byCharWrapping // 글자 단위로 줄바꿈 (디폴트는 어절 단위)
        
        self.addSubview(titleLabel)
        titleLabel.snp.makeConstraints {
          $0.top.bottom.equalToSuperview().inset(10)
          $0.left.right.equalToSuperview().inset(16)
        }
      }​
  • 사용하는 쪽
    import UIKit
    import SnapKit
    
    class ViewController: UIViewController {
      private let width = 177.0
      private let height = 56.0
      
      private lazy var myView = MyTopTipView(
        viewColor: UIColor.systemOrange,
        tipStartX: 70.5,
        tipWidth: 11.0,
        tipHeight: 6.0
      )
      
      override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.addSubview(self.myView)
        self.myView.snp.makeConstraints {
          $0.center.equalToSuperview()
          $0.width.equalTo(self.width)
        }
      }
    }​

* 전체 코드: https://github.com/JK0369/ExTipView

Comments