123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- //
- // Created by Tom Baranes on 21/08/16.
- // Copyright © 2016 IBAnimatable. All rights reserved.
- //
- import UIKit
- enum ActivityIndicatorShape {
- case circle
- case circleSemi
- case ring
- case ringTwoHalfVertical
- case ringTwoHalfHorizontal
- case ringThirdFour
- case rectangle
- case triangle
- case offsetTriangle
- case line
- case pacman
- case stroke
- case mask(type: MaskType)
- }
- extension ActivityIndicatorShape {
- func makeLayer(size: CGSize, color: UIColor) -> CALayer {
- let path = self.path(size: size)
- let drawingMode = self.drawingMode(size: size)
- return ActivityIndicatorShape.makeShapeLayer(with: size,
- color: color,
- path: path,
- mode: drawingMode)
- }
- func path(size: CGSize) -> UIBezierPath {
- switch self {
- case .circle:
- return makeCirclePath(with: size)
- case .circleSemi:
- return makeSemiCirclePath(with: size)
- case .ring:
- return makeRingPath(with: size)
- case .ringTwoHalfVertical:
- return makeRingTwoHalfVerticalPath(with: size)
- case .ringTwoHalfHorizontal:
- return makeRingTwoHalfHorizontalPath(with: size)
- case .ringThirdFour:
- return makeRingThirdFourPath(with: size)
- case .rectangle:
- return makeRectanglePath(with: size)
- case .triangle:
- return makeTrianglePath(with: size)
- case .offsetTriangle:
- return makeOffsetTrianglePath(with: size)
- case .line:
- return makeLinePath(with: size)
- case .pacman:
- return makePacmanPath(with: size)
- case .stroke:
- return makeStrokePath(with: size)
- case .mask(let type):
- return makeMaskPath(with: size, type: type)
- }
- }
- fileprivate func drawingMode(size: CGSize) -> CAShapeLayer.DrawingMode {
- switch self {
- case .ring, .ringTwoHalfVertical, .ringTwoHalfHorizontal, .ringThirdFour, .stroke:
- return .stroke(lineWidth: 2)
- case .pacman:
- return .stroke(lineWidth: size.width / 2)
- default:
- return .fill
- }
- }
- }
- private extension ActivityIndicatorShape {
- static func makeShapeLayer(with size: CGSize, color: UIColor, path: UIBezierPath, mode: CAShapeLayer.DrawingMode) -> CAShapeLayer {
- let layer = CAShapeLayer()
- layer.apply(mode: mode, color: color)
- layer.backgroundColor = nil
- layer.path = path.cgPath
- layer.frame = size.rect
- return layer
- }
- }
- // MARK: - Circles
- private extension ActivityIndicatorShape {
- func makeCirclePath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: 0,
- endAngle: 2 * CGFloat.pi,
- clockwise: false)
- return path
- }
- func makeSemiCirclePath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: -CGFloat.pi / 6,
- endAngle: -5 * CGFloat.pi / 6,
- clockwise: false)
- path.close()
- return path
- }
- }
- // MARK: - Rings
- private extension ActivityIndicatorShape {
- func makeRingPath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: 0,
- endAngle: 2 * CGFloat.pi,
- clockwise: false)
- return path
- }
- func makeRingTwoHalfVerticalPath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: -3 * CGFloat.pi / 4,
- endAngle: -CGFloat.pi / 4,
- clockwise: true)
- path.move(
- to: CGPoint(x: size.width / 2 - size.width / 2 * cos(.pi / 4),
- y: size.height / 2 + size.height / 2 * sin(.pi / 4))
- )
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: -5 * .pi / 4,
- endAngle: -7 * .pi / 4,
- clockwise: false)
- return path
- }
- func makeRingTwoHalfHorizontalPath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: 3 * .pi / 4,
- endAngle: 5 * .pi / 4,
- clockwise: true)
- path.move(
- to: CGPoint(x: size.width / 2 + size.width / 2 * cos(.pi / 4),
- y: size.height / 2 - size.height / 2 * sin(.pi / 4))
- )
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: -.pi / 4,
- endAngle: .pi / 4,
- clockwise: true)
- return path
- }
- func makeRingThirdFourPath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: -3 * .pi / 4,
- endAngle: -.pi / 4,
- clockwise: false)
- return path
- }
- }
- // MARK: - Others
- private extension ActivityIndicatorShape {
- func makeRectanglePath(with size: CGSize) -> UIBezierPath {
- return UIBezierPath(rect: size.rect)
- }
- func makeOffsetTrianglePath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- let offsetY = size.height / 4
- path.move(to: CGPoint(x: 0, y: size.height - offsetY))
- path.addLine(to: CGPoint(x: size.width / 2, y: size.height / 2 - offsetY))
- path.addLine(to: CGPoint(x: size.width, y: size.height - offsetY))
- path.close()
- return path
- }
- func makeTrianglePath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.move(to: size.bottomLeft)
- path.addLine(to: size.center)
- path.addLine(to: size.bottomRight)
- path.close()
- return path
- }
- func makeLinePath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath(roundedRect: size.rect,
- cornerRadius: size.width / 2)
- return path
- }
- func makeStrokePath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.addArc(withCenter: size.center,
- radius: size.width / 2,
- startAngle: -(.pi / 2),
- endAngle: .pi + .pi / 2,
- clockwise: true)
- return path
- }
- func makePacmanPath(with size: CGSize) -> UIBezierPath {
- let path = UIBezierPath()
- path.addArc(withCenter: size.center,
- radius: size.width / 4,
- startAngle: 0,
- endAngle: 2 * .pi,
- clockwise: true)
- return path
- }
- func makeMaskPath(with size: CGSize, type: MaskType) -> UIBezierPath {
- return type.bezierPath(in: size.rect)
- }
- }
- // MARK: - CAShapeLayer
- extension CAShapeLayer {
- enum DrawingMode {
- case fill
- case stroke(lineWidth: CGFloat)
- case fillStroke(lineWidth: CGFloat)
- }
- func apply(mode: DrawingMode, color: UIColor) {
- switch mode {
- case .fill:
- self.fillColor = color.cgColor
- case .stroke(let lineWidth):
- self.strokeColor = color.cgColor
- self.lineWidth = lineWidth
- self.fillColor = nil
- case .fillStroke(let lineWidth):
- self.strokeColor = color.cgColor
- self.lineWidth = lineWidth
- self.fillColor = color.cgColor
- }
- }
- }
- private extension CGSize {
- var rect: CGRect {
- return CGRect(origin: .zero, size: self)
- }
- var center: CGPoint {
- return CGPoint(x: self.width / 2, y: self.height / 2)
- }
- var bottomRight: CGPoint {
- return CGPoint(x: self.width, y: self.height)
- }
- var bottomLeft: CGPoint {
- return CGPoint(x: 0, y: self.height)
- }
- }
|