-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into setting/#198
- Loading branch information
Showing
70 changed files
with
2,837 additions
and
817 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
TOASTER-iOS/Global/Components/ToasterLoadingView/ToasterLoadingView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// | ||
// ToasterLoadingView.swift | ||
// TOASTER-iOS | ||
// | ||
// Created by 민 on 10/7/24. | ||
// | ||
|
||
import UIKit | ||
|
||
import SnapKit | ||
|
||
final class ToasterLoadingView: UIView { | ||
|
||
// MARK: - Properties | ||
|
||
/// 현재 로딩 뷰의 애니메이션이 동작하고 있는지를 Bool 값으로 반환 | ||
private(set) var isAnimating: Bool = false | ||
|
||
/// 애니메이션이 중단될 때 로딩 뷰를 사라지게할지/말지를 Bool 값으로 결정 | ||
var hidesWhenStopped: Bool = true | ||
|
||
// MARK: - UI Components | ||
|
||
private let backgroundShapeLayer = CAShapeLayer() | ||
private let loadingShapeLayer = CAShapeLayer() | ||
|
||
// MARK: - Life Cycles | ||
|
||
override init(frame: CGRect) { | ||
super.init(frame: frame) | ||
setupStyle() | ||
setupHierarchy() | ||
} | ||
|
||
@available(*, unavailable) | ||
required init?(coder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
override func layoutSubviews() { | ||
super.layoutSubviews() | ||
setupLayers() | ||
} | ||
} | ||
|
||
// MARK: - Extensions | ||
|
||
extension ToasterLoadingView { | ||
/// 커스텀 로딩 애니메이션을 시작합니다 | ||
func startAnimation() { | ||
guard !isAnimating else { return } | ||
|
||
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation") | ||
rotationAnimation.toValue = 2 * CGFloat.pi | ||
rotationAnimation.duration = 1 | ||
rotationAnimation.isRemovedOnCompletion = false | ||
rotationAnimation.repeatCount = .infinity | ||
|
||
layer.add(rotationAnimation, forKey: "rotationAnimation") | ||
|
||
isAnimating = true | ||
if hidesWhenStopped { self.isHidden = false } | ||
} | ||
|
||
/// 커스텀 로딩 애니메이션을 멈춥니다 | ||
func stopAnimation() { | ||
guard isAnimating else { return } | ||
layer.removeAnimation(forKey: "rotationAnimation") | ||
|
||
isAnimating = false | ||
if hidesWhenStopped { self.isHidden = true } | ||
} | ||
} | ||
|
||
// MARK: - Private Extensions | ||
|
||
private extension ToasterLoadingView { | ||
func setupStyle() { | ||
backgroundShapeLayer.do { | ||
$0.strokeColor = UIColor.toasterWhite.cgColor | ||
$0.fillColor = UIColor.clear.cgColor | ||
} | ||
|
||
loadingShapeLayer.do { | ||
$0.strokeColor = UIColor.black850.cgColor | ||
$0.fillColor = UIColor.clear.cgColor | ||
$0.strokeEnd = 0.25 | ||
$0.lineCap = .round | ||
} | ||
} | ||
|
||
func setupLayers() { | ||
let centerPoint = CGPoint(x: frame.width / 2, y: bounds.height / 2) | ||
let radius = bounds.width / 2 | ||
|
||
// 흰색 부분의 동그라미 배경 경로 | ||
let backgroundPath = UIBezierPath( | ||
arcCenter: centerPoint, | ||
radius: radius, | ||
startAngle: 0, | ||
endAngle: 2 * CGFloat.pi, | ||
clockwise: true | ||
) | ||
backgroundShapeLayer.path = backgroundPath.cgPath | ||
backgroundShapeLayer.lineWidth = radius / 3 | ||
|
||
// 검정색 실제 로딩이 되는 부분의 경로 | ||
let loadingPath = UIBezierPath( | ||
arcCenter: centerPoint, | ||
radius: radius, | ||
startAngle: 0, | ||
endAngle: 2 * CGFloat.pi, | ||
clockwise: true | ||
) | ||
loadingShapeLayer.path = loadingPath.cgPath | ||
loadingShapeLayer.lineWidth = radius / 3 | ||
} | ||
|
||
func setupHierarchy() { | ||
[backgroundShapeLayer, loadingShapeLayer].forEach { | ||
layer.addSublayer($0) | ||
} | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
TOASTER-iOS/Global/Components/ToasterTipView/TipPathView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// | ||
// TipType.swift | ||
// TOASTER-iOS | ||
// | ||
// Created by 민 on 10/11/24. | ||
// | ||
|
||
import UIKit | ||
|
||
import SnapKit | ||
|
||
enum TipType { | ||
case top, bottom, left, right | ||
} | ||
|
||
final class TipPathView: UIView { | ||
|
||
// MARK: - Properties | ||
|
||
private var tipType: TipType | ||
|
||
private let arrowWidth: CGFloat = 10.0 | ||
private let arrowHeight: CGFloat = 9.0 | ||
|
||
// MARK: - UI Components | ||
|
||
private let tipPath = UIBezierPath() | ||
|
||
// MARK: - Life Cycles | ||
|
||
init(tipType: TipType) { | ||
self.tipType = tipType | ||
super.init(frame: .zero) | ||
} | ||
|
||
@available(*, unavailable) | ||
required init?(coder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
override func draw(_ rect: CGRect) { | ||
switch tipType { | ||
case .top: drawTopTip(rect) | ||
case .bottom: drawBottomTip(rect) | ||
case .left: drawLeftTip(rect) | ||
case .right: drawRightTip(rect) | ||
} | ||
setupTip() | ||
} | ||
} | ||
|
||
// MARK: - Private Extensions | ||
|
||
private extension TipPathView { | ||
func setupTip() { | ||
tipPath.do { | ||
$0.lineJoinStyle = .round | ||
$0.lineWidth = 2 | ||
tipPath.close() | ||
UIColor.black900.setStroke() | ||
tipPath.stroke() | ||
UIColor.black900.setFill() | ||
tipPath.fill() | ||
} | ||
} | ||
|
||
/// 팁이 상단에 위치했을 때 - 아래를 가리키는 방향 | ||
func drawTopTip(_ rect: CGRect) { | ||
tipPath.move(to: CGPoint(x: rect.midX - arrowWidth/2, y: rect.maxY - arrowHeight)) | ||
tipPath.addLine(to: CGPoint(x: rect.midX, y: rect.maxY)) | ||
tipPath.addLine(to: CGPoint(x: rect.midX + arrowWidth/2, y: rect.maxY - arrowHeight)) | ||
} | ||
|
||
/// 팁이 하단에 위치했을 때 - 위를 가리키는 방향 | ||
func drawBottomTip(_ rect: CGRect) { | ||
tipPath.move(to: CGPoint(x: rect.midX - arrowWidth/2, y: rect.minY + arrowHeight)) | ||
tipPath.addLine(to: CGPoint(x: rect.midX, y: rect.minY)) | ||
tipPath.addLine(to: CGPoint(x: rect.midX + arrowWidth/2, y: rect.minY + arrowHeight)) | ||
} | ||
|
||
/// 팁이 좌측에 위치했을 때 - 오른쪽을 가리키는 방향 | ||
func drawLeftTip(_ rect: CGRect) { | ||
tipPath.move(to: CGPoint(x: rect.maxX - arrowHeight, y: rect.midY - arrowWidth/2)) | ||
tipPath.addLine(to: CGPoint(x: rect.maxX, y: rect.midY)) | ||
tipPath.addLine(to: CGPoint(x: rect.maxX - arrowHeight, y: rect.midY + arrowWidth/2)) | ||
} | ||
|
||
/// 팁이 우측에 위치했을 때 - 왼쪽을 가리키는 방향 | ||
func drawRightTip(_ rect: CGRect) { | ||
tipPath.move(to: CGPoint(x: rect.minX + arrowHeight, y: rect.midY - arrowWidth/2)) | ||
tipPath.addLine(to: CGPoint(x: rect.minX, y: rect.midY)) | ||
tipPath.addLine(to: CGPoint(x: rect.minX + arrowHeight, y: rect.midY + arrowWidth/2)) | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
TOASTER-iOS/Global/Components/ToasterTipView/TipUserDefaults.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// | ||
// TipUserDefaults.swift | ||
// TOASTER-iOS | ||
// | ||
// Created by 민 on 10/29/24. | ||
// | ||
|
||
import Foundation | ||
|
||
enum TipUserDefaults { | ||
static let isShowHomeViewToolTip = "homeViewToolTip" | ||
static let isShowDetailClipViewToolTip = "detailClipViewToolTip" | ||
static let isShowLinkWebViewToolTip = "linkWebViewToolTip" | ||
} |
Oops, something went wrong.