Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- Xcode
- ribs
- UICollectionView
- 리팩토링
- map
- Protocol
- Clean Code
- 스위프트
- rxswift
- Refactoring
- uitableview
- swift documentation
- HIG
- combine
- 클린 코드
- RxCocoa
- clean architecture
- 리펙토링
- collectionview
- uiscrollview
- swiftUI
- MVVM
- 리펙터링
- tableView
- Observable
- ios
- SWIFT
- UITextView
- Human interface guide
- 애니메이션
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] UIBezierPath, CAShapeLayer으로 말풍선 구현 본문
View 사용하여 구현 (가장 간편)
- 사각형 View위에 작은 tip 추가
- topView에 path와 layer설정하여 구현
- 좀더 구체적인 예제, 커스텀 뷰로 만드는 방법은 말풍선 뷰 구현 포스팅 글 참고
import UIKit
import SnapKit
class ViewController: UIViewController {
private let width = 120.0
private let height = 120.0
private let someView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
self.someView.backgroundColor = .systemOrange
self.view.addSubview(self.someView)
self.someView.snp.makeConstraints {
$0.size.equalTo(120)
$0.center.equalToSuperview()
}
let path = CGMutablePath()
path.move(to: CGPoint(x: self.width / 2 - 10, y: 0)) // 시작 위치
path.addLine(to: CGPoint(x: self.width / 2, y: -10))
path.addLine(to: CGPoint(x: self.width / 2 + 10, y: 0))
path.addLine(to: CGPoint(x: 0, y: 0))
let shape = CAShapeLayer()
shape.path = path
shape.fillColor = UIColor.gray.cgColor
self.someView.layer.insertSublayer(shape, at: 0)
}
}
Only code 구현 (새로운 뷰 사용 x)
UIView위에 그림을 그리는 원리
- UIBezierPath로 테두리 밑그림
- CASahpeLayer에 UIBezierPath객체를 이용해서 색칠 후 UIView.layer.addSublayer
- 말풍선을 그리기 위해, custom view (xib) 안에 tip 그림을 그려서 구현
- UIView에서 override할수 있도록 제공하는 draw(_ rect:CGRect) 이용
- UIBezierPath, CAShapeLayer 개념 참고: ios-development.tistory.com/265
UIBezierPath로 밑그림
- custom view로 만든 BallonView에서 draw(_ rect: CGRect) 함수를 override하여 구현
- custom view 만드는 방법 참고 - BallonView
//
// BalloonView.swift
// Balloon
//
// Created by 김종권 on 2021/03/25.
//
import Foundation
import UIKit
class BalloonView: UIView {
@IBOutlet weak var messageLabel: UILabel!
@IBOutlet weak var containerStackView: UIStackView!
required init?(coder: NSCoder) {
super.init(coder: coder)
setUp()
}
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
override class func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
}
private func setUp() {
guard let balloonView = loadViewFromNib(nib: "BalloonView") else {
return
}
addSubview(balloonView)
// 생성된 뷰의 위치 설정: bottom + centerX
balloonView.translatesAutoresizingMaskIntoConstraints = false
balloonView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
balloonView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
// 생성된 뷰의 내부 내용에 따른 자동 크기 조절: 현재 view의 width, height 동적으로 조정
translatesAutoresizingMaskIntoConstraints = false
widthAnchor.constraint(equalTo: balloonView.widthAnchor).isActive = true
heightAnchor.constraint(equalTo: balloonView.heightAnchor).isActive = true
}
}
extension UIView {
func loadViewFromNib(nib: String) -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nib, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
- 말풍선 밑 tip의 높이와 width 정의
class BalloonView: UIView {
...
let tipHeight: CGFloat = 6.0
let tipWidth: CGFloat = 10.0
...
}
- draw(_ rect: CGRect) 함수를 override하여 tip 이미지 구현
class BalloonView: UIView {
...
override func draw(_ rect: CGRect) {
super.draw(rect)
// 위치 정의
let tipLeft = rect.origin.x + (rect.size.width / 2.0) - (tipWidth / 2.0)
let tipBottom = CGPoint(x: rect.origin.x + (rect.size.width / 2.0), y: containerStackView.bounds.size.height + tipHeight)
let heightWithoutTip = containerStackView.bounds.size.height - 1
// path 객체로 선분을 잇는 작업
let path = UIBezierPath()
path.move(to: CGPoint(x: tipLeft, y: heightWithoutTip))
path.addLine(to: CGPoint(x: tipBottom.x, y: tipBottom.y))
path.addLine(to: CGPoint(x: tipLeft + tipWidth, y: heightWithoutTip))
path.close()
// 만든 path 객체를 이용하여 shapeLayer로 색칠, layer.addSublayer에 사용
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = containerStackView.backgroundColor?.cgColor
containerStackView.layer.addSublayer(shapeLayer)
// masksToBounds = true가 되면 tip이미지가 사라지는 현상
containerStackView.layer.masksToBounds = false
// layer의 zPositino default값은 0이므로, 다른 객체보다 앞에 위치하여 보이게끔 설정
containerStackView.layer.zPosition = 1
}
...
}
'iOS 응용 (swift)' 카테고리의 다른 글
[iOS - swift] UIGraphicsBeginImageContextWithOptions, 그래픽 UIImage 생성 (0) | 2021.03.29 |
---|---|
[iOS - swift] CAGradientLayer, layer.mask (+ 텍스트 gradient fade out 처리) (0) | 2021.03.26 |
[iOS - swift] custom view (xib) 내부 내용에 따라 동적으로 크기 조절 (0) | 2021.03.25 |
[iOS - swift] 빈 화면 탭 시 키보드 내리는 방법 (화면 터치 시 키보드 숨김처리) (0) | 2021.03.22 |
[iOS - swift] long touch 시 개발자모드 불러오기 (0) | 2021.03.22 |
Comments