2023.11.03 (금)
미션을 수행하면 표시될 progress bar 작업을 진행했다.
이미지 위에 원형 프로그래스 바를 직접 구현하여 미션 수행 상황을 한 눈에 볼 수 있도록 하였다.
미션 수행 내역이 한 번이라도 있는 경우, 이미지 위에 회색 및 흰색 테두리가 표시되고, 그 위에 파란색으로 진행상황을 표시해주는 방식이다.
1. CircularProgressBar 클래스 생성
다음과 같이 클래스로 원형 프로그래스 바를 생성해두면, var progressBar = CircularProgressBar() 이런 식으로 간편하게 사용이 가능하다.
class CircularProgressBar: UIView {
private let lineWidth: CGFloat = 2
}
2. 프로그래스가 표시될 기본 배경 stroke 그려주기
draw(_:) 에서 UIBezierPath 를 이용해 배경 stroke 를 그려준다.
이 draw 메서드는 UIView에서 기본 구현이 되어 있어, 따로 호출하지 않아도 CircularProgressBar 가 초기화 될 때 자동으로 불리기 때문에 배경 stroke 만 우선 먼저 그려주자.
draw 메서드 내에서는 해당 view 의 frame이 자동으로 반영이 되어 따로 rect 를 설정해 줄 필요가 없다.
override func draw(_ rect: CGRect) {
super.draw(rect)
let path = UIBezierPath()
path.addArc(withCenter: CGPoint(x: rect.midX, y: rect.midY),
radius: rect.midX - (lineWidth / 2),
startAngle: 0,
endAngle: 2 * .pi,
clockwise: true)
path.lineWidth = lineWidth
MacaColors.gray200.set()
path.stroke()
}
UIBezierPath 에 addArc 를 사용해 path 를 그려준다.
- withCenter : 그려줄 곡선의 중심점
- radius : 곡선의 반지름
- startAngle : 곡선의 시작점 (* 0으로 설정하면 12시 방향이 아니고 9시 방향임. 아래에서 설명 계속,,)
- endAngle : 곡선의 종료점
- clockwise : 시계 방향 / 반시계 방향
3. 프로그래스 바 그려주기
func setProgress(diameter: CGFloat, progress: Double) {
backgroundColor = .clear
let rect = CGRect(x: .zero, y: .zero, width: diameter, height: diameter)
let startAngle = CGFloat.pi / 2
let circularPath = UIBezierPath(arcCenter: CGPoint(x: rect.midX, y: rect.midY),
radius: rect.midX - (lineWidth / 2),
startAngle: -startAngle,
endAngle: (.pi * 2) * progress - startAngle,
clockwise: true)
let circularLayer = CAShapeLayer()
circularLayer.path = circularPath.cgPath
circularLayer.fillColor = UIColor.clear.cgColor
circularLayer.strokeColor = MacaColors.skyBlue700.cgColor
circularLayer.lineWidth = lineWidth
//circularLayer.lineCap = .round
self.layer.addSublayer(circularLayer)
}
1) 곡선을 그릴 위치와 크기 설정 - CGRect
CGRect 를 self.bounds 나 frame 을 사용해서 설정해주니까 width, height 값이 0으로 적용되어 곡선이 제대로 그려지지 않았다.
그래서 그려줄 곡선의 지름을 받아와 rect 를 설정해 주었다.
2) 시작점 설정
startAngle 을 0으로 설정해두면 12시 방향이 아니라 9시 방향에서부터 시작하기 때문에, 12시 방향에서부터 시작하고 싶다면
시작점을 -CGFloat.pi / 2 로 설정해두어야 함.
3) 종료 위치 설정
** 파이 너무 오랜만이라 헷갈려서 다시 찾아봄,, ㅎㅎ 파이(π)는 원주율, 즉 원의 지름에 대한 둘레의 비율을 뜻한다.
endAngle 을 설정할 때, 원의 둘레에 progress 를 곱한 만큼 표시를 해주어야 하므로 (.pi * 2) * progress 이렇게 설정을 해줘야 한다. 그리고 startAngle이 0 이 아니었으니깐 여기서 startAngle 만큼 또 빼주기.
4) 레이어에 path 입히기 - CAShapeLayer()
위의 draw 메서드에서는 자동으로 그려주었지만, path로 입혀줘야댐 (아닌가? 다시 확인해보자)
그려준 곡선 path 를 레이어에 입힌 후, addSublayer로 레이어를 추가해준다.
+ 나는 그냥 view 가 세팅될 때 프로그래스 상황을 초기화 해주기만 하면 되니까 setProgress 함수를 만들어 구현을 해주었지만,
progress value 에 따라 프로그래스 바가 계속 업데이트 되어야 한다면 value 값이 변경될 때마다 프로그래스 바를 갱신할 수 있도록 didset 이나 옵저버블을 사용하여 동기화를 시켜줘도 좋을 듯 하다.
처음에 시안 보고 매우 귀찮아 보였는데, 하고 보니 생각보다 별로 안어렵고 재밌었둠 ㅎㅎ
예뿌다
코드 전문
final class CircularProgressBar: UIView {
private let lineWidth: CGFloat = 2
func setProgress(diameter: CGFloat, progress: Double) {
backgroundColor = .clear
let rect = CGRect(x: .zero, y: .zero, width: diameter, height: diameter)
let startAngle = CGFloat.pi / 2
let circularPath = UIBezierPath(arcCenter: CGPoint(x: rect.midX, y: rect.midY),
radius: rect.midX - (lineWidth / 2),
startAngle: -startAngle,
endAngle: (.pi * 2) * progress - startAngle,
clockwise: true)
let circularLayer = CAShapeLayer()
circularLayer.path = circularPath.cgPath
circularLayer.fillColor = UIColor.clear.cgColor
circularLayer.strokeColor = MacaColors.skyBlue700.cgColor
circularLayer.lineWidth = 2
//circularLayer.lineCap = .round
self.layer.addSublayer(circularLayer)
}
override func draw(_ rect: CGRect) {
super.draw(rect)
let outerPath = UIBezierPath()
outerPath.addArc(withCenter: CGPoint(x: rect.midX, y: rect.midY),
radius: rect.midX - (lineWidth / 2),
startAngle: 0,
endAngle: 2 * .pi,
clockwise: true)
outerPath.lineWidth = lineWidth
MacaColors.gray200.set()
outerPath.stroke()
let innerPath = UIBezierPath()
innerPath.addArc(withCenter: CGPoint(x: rect.midX, y: rect.midY),
radius: rect.midX - lineWidth - (lineWidth / 2),
startAngle: 0,
endAngle: 2 * .pi,
clockwise: true)
innerPath.lineWidth = lineWidth
UIColor.white.set()
innerPath.stroke()
}
}
'초보 iOS 개발자의 일상 > 개발 업무' 카테고리의 다른 글
[iOS] 네트워크 속도 제어 (iPhone & Mac) (0) | 2024.01.25 |
---|---|
[Swift] bullet string 적용하기 (0) | 2023.12.26 |
iOS 17 대응 - 컬렉션뷰 이슈 (0) | 2023.09.27 |
[Swift iOS] Set gradient 그라디언트 뷰 적용하는 법 (+ 안뜰때!!) (1) | 2023.06.28 |
즐겨찾기 추가 및 삭제 토스트 띄우기 - 광클 시 문제점 (0) | 2023.01.14 |