From 0e20b0fb0e02810a6a93a5e0eb2550c6d4e857d6 Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Fri, 11 Mar 2022 13:55:56 +0100 Subject: [PATCH 1/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20::=20Extract=20config?= =?UTF-8?q?=20for=20notch=20into=20separate=20struct?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This struct is available per device as an extension on `NotchGradientLoadingBarViewModel.SafeAreaDevice` --- .../NotchGradientLoadingBarController.swift | 163 +++++++++--------- 1 file changed, 80 insertions(+), 83 deletions(-) diff --git a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift index 1ad0ac1..10998a3 100644 --- a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift +++ b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift @@ -8,51 +8,31 @@ import UIKit +// MARK: - Types + +private struct NotchConfig { + /// The width of the iPhone notch. + let notchWidth: CGFloat + + /// The radius of the small circle on the outside of the notch. + let smallCircleRadius: CGFloat = 6 + + /// The radius of the large circle on the inside of the notch. + let largeCircleRadius: CGFloat + + /// We're moving the the large-circles a bit up. + /// This prevents having a straight line between the circles. + /// See + let verticalOffsetForLargeCircle: CGFloat + + /// The transform to be applied to the bezier path. + let transform: CGAffineTransform +} + /// Type-alias for the controller to be more similar to the pod name. public typealias NotchGradientLoadingBar = NotchGradientLoadingBarController open class NotchGradientLoadingBarController: GradientLoadingBarController { - // MARK: - Config - - private struct Config { - /// The default configuration for the iPhone X and 11. - /// Values are based on . - static let `default` = Config(notchWidth: 208, - largeCircleRadius: 22.5, - verticalOffsetForLargeCircle: -4.75, - transform: CGAffineTransform(translationX: 0.33, y: 0)) - - /// The iPhone 12 specific configuration. - static let iPhone12Device = Config(notchWidth: 209.5, - largeCircleRadius: 21, - verticalOffsetForLargeCircle: -1.75, - transform: .identity) - - // The iPhone 13 specific configuration: ‟iPhone 13 notch is 20% smaller in width, but it is also a little taller in height‟. - // Source: . - static let iPhone13Device = Config(notchWidth: 161, - largeCircleRadius: 22, - verticalOffsetForLargeCircle: -1, - transform: .identity) - - /// The width of the iPhone notch. - let notchWidth: CGFloat - - /// The radius of the small circle on the outside of the notch. - let smallCircleRadius: CGFloat = 6 - - /// The radius of the large circle on the inside of the notch. - let largeCircleRadius: CGFloat - - /// We're moving the the large-circles a bit up. - /// This prevents having a straight line between the circles. - /// See - let verticalOffsetForLargeCircle: CGFloat - - /// The transform to be applied to the bezier path. - let transform: CGAffineTransform - } - // MARK: - Private properties private let viewModel = NotchGradientLoadingBarViewModel() @@ -83,19 +63,7 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // As we currently only support portrait mode (and no device rotation), we can safely use `bounds.size.width` here. let screenWidth = superview.bounds.size.width - let config: Config - switch viewModel.safeAreaDevice { - case .unknown, .iPhoneX, .iPhone11: - config = .default - - case .iPhone12: - config = .iPhone12Device - - case .iPhone13: - config = .iPhone13Device - } - - let notchBezierPath = self.notchBezierPath(for: screenWidth, config: config) + let notchBezierPath = self.notchBezierPath(for: screenWidth, notchConfig: viewModel.safeAreaDevice.notchConfig) // Setting the `lineWidth` draws a line, where the actual path is exactly in the middle of the drawn line. // To get the correct height (including the path) we have to add the `height` here to the given bounds (half height for top, half for bottom). @@ -114,14 +82,14 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // MARK: - Private methods // swiftlint:disable:next function_body_length - private func notchBezierPath(for screenWidth: CGFloat, config: Config) -> UIBezierPath { + private func notchBezierPath(for screenWidth: CGFloat, notchConfig: NotchConfig) -> UIBezierPath { // We always center the notch in the middle of the screen. - let leftNotchPoint = (screenWidth - config.notchWidth) / 2 - let rightNotchPoint = (screenWidth + config.notchWidth) / 2 + let leftNotchPoint = (screenWidth - notchConfig.notchWidth) / 2 + let rightNotchPoint = (screenWidth + notchConfig.notchWidth) / 2 // The center point of the large circles lays at the bottom of the small circles. // See graphic https://www.paintcodeapp.com/news/iphone-x-screen-demystified for further details. - let smallCircleDiameter: CGFloat = 2 * config.smallCircleRadius + let smallCircleDiameter: CGFloat = 2 * notchConfig.smallCircleRadius // Reducing the height here a little in order to match the "basic" gradient loading bar. let height = self.height - 0.5 @@ -130,43 +98,43 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { bezierPath.move(to: .zero) // Draw line to small-circle left to `leftNotchPoint`. - bezierPath.addLineTo(x: leftNotchPoint - config.smallCircleRadius, + bezierPath.addLineTo(x: leftNotchPoint - notchConfig.smallCircleRadius, y: 0) // Draw the small circle left to the `leftNotchPoint`. // See for the definition of the // angles in the default coordinate system. - bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - config.smallCircleRadius, - y: config.smallCircleRadius), - radius: config.smallCircleRadius, + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - notchConfig.smallCircleRadius, + y: notchConfig.smallCircleRadius), + radius: notchConfig.smallCircleRadius, startAngle: -CGFloat.pi / 2, endAngle: 0, clockwise: true) // Draw the large circle right to the `leftNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint + config.largeCircleRadius, - y: smallCircleDiameter + config.verticalOffsetForLargeCircle), - radius: config.largeCircleRadius, + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint + notchConfig.largeCircleRadius, + y: smallCircleDiameter + notchConfig.verticalOffsetForLargeCircle), + radius: notchConfig.largeCircleRadius, startAngle: CGFloat.pi, endAngle: CGFloat.pi / 2, clockwise: false) // Draw line to large-circle underneath and left to `rightNotchPoint`. - bezierPath.addLineTo(x: rightNotchPoint - config.largeCircleRadius, - y: smallCircleDiameter + config.largeCircleRadius + config.verticalOffsetForLargeCircle) + bezierPath.addLineTo(x: rightNotchPoint - notchConfig.largeCircleRadius, + y: smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.verticalOffsetForLargeCircle) // Draw the large circle left to the `rightNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint - config.largeCircleRadius, - y: smallCircleDiameter + config.verticalOffsetForLargeCircle), - radius: config.largeCircleRadius, + bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint - notchConfig.largeCircleRadius, + y: smallCircleDiameter + notchConfig.verticalOffsetForLargeCircle), + radius: notchConfig.largeCircleRadius, startAngle: CGFloat.pi / 2, endAngle: 0, clockwise: false) // Draw the small circle right to the `rightNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint + config.smallCircleRadius, - y: config.smallCircleRadius), - radius: config.smallCircleRadius, + bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint + notchConfig.smallCircleRadius, + y: notchConfig.smallCircleRadius), + radius: notchConfig.smallCircleRadius, startAngle: CGFloat.pi, endAngle: CGFloat.pi + CGFloat.pi / 2, clockwise: true) @@ -177,7 +145,7 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // And all the way back.. // Have the small-circle at the bottom-path only ⅔ of the size of the upper-path produced visually better results. - let bottomPathSmallCircleRadius = (config.smallCircleRadius / 3) * 2 + let bottomPathSmallCircleRadius = (notchConfig.smallCircleRadius / 3) * 2 // Draw line down. bezierPath.addLineTo(x: screenWidth, @@ -196,21 +164,21 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { clockwise: false) // Draw the large circle left to the `rightNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: height + rightNotchPoint - config.largeCircleRadius, - y: height + smallCircleDiameter + config.verticalOffsetForLargeCircle), - radius: config.largeCircleRadius, + bezierPath.addArc(withCenter: CGPoint(x: height + rightNotchPoint - notchConfig.largeCircleRadius, + y: height + smallCircleDiameter + notchConfig.verticalOffsetForLargeCircle), + radius: notchConfig.largeCircleRadius, startAngle: 0, endAngle: CGFloat.pi / 2, clockwise: true) // Draw line to large-circle underneath and right to `leftNotchPoint` - bezierPath.addLineTo(x: height + leftNotchPoint + config.largeCircleRadius, - y: height + smallCircleDiameter + config.largeCircleRadius + config.verticalOffsetForLargeCircle) + bezierPath.addLineTo(x: height + leftNotchPoint + notchConfig.largeCircleRadius, + y: height + smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.verticalOffsetForLargeCircle) // Draw the large circle right to the `leftNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - height + config.largeCircleRadius, - y: height + smallCircleDiameter + config.verticalOffsetForLargeCircle), - radius: config.largeCircleRadius, + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - height + notchConfig.largeCircleRadius, + y: height + smallCircleDiameter + notchConfig.verticalOffsetForLargeCircle), + radius: notchConfig.largeCircleRadius, startAngle: CGFloat.pi / 2, endAngle: CGFloat.pi, clockwise: true) @@ -227,7 +195,7 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { bezierPath.addLineTo(x: 0, y: height) bezierPath.close() - bezierPath.apply(config.transform) + bezierPath.apply(notchConfig.transform) return bezierPath } @@ -247,6 +215,35 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // MARK: - Helpers +private extension NotchGradientLoadingBarViewModel.SafeAreaDevice { + /// The notch specific configuration for the current device. + var notchConfig: NotchConfig { + switch self { + case .unknown, .iPhoneX, .iPhone11: + /// The default configuration for the iPhone X and 11. + /// Values are based on . + return NotchConfig(notchWidth: 208, + largeCircleRadius: 22.5, + verticalOffsetForLargeCircle: -4.75, + transform: CGAffineTransform(translationX: 0.33, y: 0)) + + case .iPhone12: + return NotchConfig(notchWidth: 209.5, + largeCircleRadius: 21, + verticalOffsetForLargeCircle: -1.75, + transform: .identity) + + case .iPhone13: + // The iPhone 13 specific configuration: ‟iPhone 13 notch is 20% smaller in width, but it is also a little taller in height‟. + // Source: . + return NotchConfig(notchWidth: 161, + largeCircleRadius: 22, + verticalOffsetForLargeCircle: -1, + transform: .identity) + } + } +} + private extension UIBezierPath { // swiftlint:disable:next identifier_name func addLineTo(x: CGFloat, y: CGFloat) { From d97b99ab8305b0d3abecb32f1119b911026d80d5 Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Fri, 11 Mar 2022 14:04:12 +0100 Subject: [PATCH 2/8] =?UTF-8?q?=E2=9C=A8=20::=20Add=20notch=20configuratio?= =?UTF-8?q?n=20for=20iPhone=20XR=20(WIP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Classes/NotchGradientLoadingBarController.swift | 6 ++++++ .../ViewModel/NotchGradientLoadingBarViewModel.swift | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift index 10998a3..afb7286 100644 --- a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift +++ b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift @@ -227,6 +227,12 @@ private extension NotchGradientLoadingBarViewModel.SafeAreaDevice { verticalOffsetForLargeCircle: -4.75, transform: CGAffineTransform(translationX: 0.33, y: 0)) + case .iPhoneXR: + return NotchConfig(notchWidth: 232, + largeCircleRadius: 21, + verticalOffsetForLargeCircle: 0, + transform: .identity) + case .iPhone12: return NotchConfig(notchWidth: 209.5, largeCircleRadius: 21, diff --git a/GradientLoadingBar/Classes/ViewModel/NotchGradientLoadingBarViewModel.swift b/GradientLoadingBar/Classes/ViewModel/NotchGradientLoadingBarViewModel.swift index 3470bbd..e35b3b9 100644 --- a/GradientLoadingBar/Classes/ViewModel/NotchGradientLoadingBarViewModel.swift +++ b/GradientLoadingBar/Classes/ViewModel/NotchGradientLoadingBarViewModel.swift @@ -14,6 +14,7 @@ final class NotchGradientLoadingBarViewModel { enum SafeAreaDevice { case unknown case iPhoneX + case iPhoneXR case iPhone11 case iPhone12 case iPhone13 @@ -39,9 +40,12 @@ private extension NotchGradientLoadingBarViewModel.SafeAreaDevice { /// Taken from init(deviceIdentifier: String) { switch deviceIdentifier { - case "iPhone10,3", "iPhone10,6", "iPhone11,2", "iPhone11,4", "iPhone11,6", "iPhone11,8": + case "iPhone10,3", "iPhone10,6", "iPhone11,2", "iPhone11,4", "iPhone11,6": self = .iPhoneX + case "iPhone11,8": + self = .iPhoneXR + case "iPhone12,1", "iPhone12,3", "iPhone12,5": self = .iPhone11 From ecad3b98b9b7bea20106d3dceaf528aec603cd14 Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Fri, 11 Mar 2022 14:08:56 +0100 Subject: [PATCH 3/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20::=20Allow=20offsettin?= =?UTF-8?q?g=20the=20large=20circle=20in=20x=20and=20y=20direction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NotchGradientLoadingBarController.swift | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift index afb7286..eea6da4 100644 --- a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift +++ b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift @@ -20,10 +20,8 @@ private struct NotchConfig { /// The radius of the large circle on the inside of the notch. let largeCircleRadius: CGFloat - /// We're moving the the large-circles a bit up. - /// This prevents having a straight line between the circles. - /// See - let verticalOffsetForLargeCircle: CGFloat + /// Offset for the center-point of the large circle. + let largeCircleOffset: CGPoint /// The transform to be applied to the bezier path. let transform: CGAffineTransform @@ -112,20 +110,20 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { clockwise: true) // Draw the large circle right to the `leftNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint + notchConfig.largeCircleRadius, - y: smallCircleDiameter + notchConfig.verticalOffsetForLargeCircle), + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint + notchConfig.largeCircleRadius + notchConfig.largeCircleOffset.x, + y: smallCircleDiameter + notchConfig.largeCircleOffset.y), radius: notchConfig.largeCircleRadius, startAngle: CGFloat.pi, endAngle: CGFloat.pi / 2, clockwise: false) // Draw line to large-circle underneath and left to `rightNotchPoint`. - bezierPath.addLineTo(x: rightNotchPoint - notchConfig.largeCircleRadius, - y: smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.verticalOffsetForLargeCircle) + bezierPath.addLineTo(x: rightNotchPoint - notchConfig.largeCircleRadius - notchConfig.largeCircleOffset.x, + y: smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.largeCircleOffset.y) // Draw the large circle left to the `rightNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint - notchConfig.largeCircleRadius, - y: smallCircleDiameter + notchConfig.verticalOffsetForLargeCircle), + bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint - notchConfig.largeCircleRadius - notchConfig.largeCircleOffset.x, + y: smallCircleDiameter + notchConfig.largeCircleOffset.y), radius: notchConfig.largeCircleRadius, startAngle: CGFloat.pi / 2, endAngle: 0, @@ -164,20 +162,20 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { clockwise: false) // Draw the large circle left to the `rightNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: height + rightNotchPoint - notchConfig.largeCircleRadius, - y: height + smallCircleDiameter + notchConfig.verticalOffsetForLargeCircle), + bezierPath.addArc(withCenter: CGPoint(x: height + rightNotchPoint - notchConfig.largeCircleRadius - notchConfig.largeCircleOffset.x, + y: height + smallCircleDiameter + notchConfig.largeCircleOffset.y), radius: notchConfig.largeCircleRadius, startAngle: 0, endAngle: CGFloat.pi / 2, clockwise: true) // Draw line to large-circle underneath and right to `leftNotchPoint` - bezierPath.addLineTo(x: height + leftNotchPoint + notchConfig.largeCircleRadius, - y: height + smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.verticalOffsetForLargeCircle) + bezierPath.addLineTo(x: height + leftNotchPoint + notchConfig.largeCircleRadius - notchConfig.largeCircleOffset.x, + y: height + smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.largeCircleOffset.y) // Draw the large circle right to the `leftNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - height + notchConfig.largeCircleRadius, - y: height + smallCircleDiameter + notchConfig.verticalOffsetForLargeCircle), + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - height + notchConfig.largeCircleRadius + notchConfig.largeCircleOffset.x, + y: height + smallCircleDiameter + notchConfig.largeCircleOffset.y), radius: notchConfig.largeCircleRadius, startAngle: CGFloat.pi / 2, endAngle: CGFloat.pi, @@ -224,19 +222,19 @@ private extension NotchGradientLoadingBarViewModel.SafeAreaDevice { /// Values are based on . return NotchConfig(notchWidth: 208, largeCircleRadius: 22.5, - verticalOffsetForLargeCircle: -4.75, + largeCircleOffset: CGPoint(x: 0, y: -4.75), transform: CGAffineTransform(translationX: 0.33, y: 0)) case .iPhoneXR: return NotchConfig(notchWidth: 232, largeCircleRadius: 21, - verticalOffsetForLargeCircle: 0, + largeCircleOffset: .zero, transform: .identity) case .iPhone12: return NotchConfig(notchWidth: 209.5, largeCircleRadius: 21, - verticalOffsetForLargeCircle: -1.75, + largeCircleOffset: CGPoint(x: 0, y: -1.75), transform: .identity) case .iPhone13: @@ -244,7 +242,7 @@ private extension NotchGradientLoadingBarViewModel.SafeAreaDevice { // Source: . return NotchConfig(notchWidth: 161, largeCircleRadius: 22, - verticalOffsetForLargeCircle: -1, + largeCircleOffset: CGPoint(x: 0, y: -1), transform: .identity) } } From e8d03a9ccc5242ec3a71dc64b7e91a03015e8c0b Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Fri, 11 Mar 2022 14:33:45 +0100 Subject: [PATCH 4/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20::=20Adapt=20configura?= =?UTF-8?q?tion=20for=20iPhone=20XR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Classes/NotchGradientLoadingBarController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift index eea6da4..3609437 100644 --- a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift +++ b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift @@ -227,8 +227,8 @@ private extension NotchGradientLoadingBarViewModel.SafeAreaDevice { case .iPhoneXR: return NotchConfig(notchWidth: 232, - largeCircleRadius: 21, - largeCircleOffset: .zero, + largeCircleRadius: 24, + largeCircleOffset: CGPoint(x: 0.5, y: -3.5), transform: .identity) case .iPhone12: From 41c084b27db3607b2636cbfe508da84e8a903031 Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Fri, 11 Mar 2022 14:45:35 +0100 Subject: [PATCH 5/8] =?UTF-8?q?=F0=9F=93=9D=20::=20Update=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NotchGradientLoadingBarController.swift | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift index 3609437..43dfac1 100644 --- a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift +++ b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift @@ -21,9 +21,14 @@ private struct NotchConfig { let largeCircleRadius: CGFloat /// Offset for the center-point of the large circle. + /// + /// - A positive value for the `X` property will move the large circles closer to the center of the screen. A negative offset closer to + /// the corners of the screen. + /// + /// - A positive value for the `Y` property will move the large circles downwards. A negative offset will move them upwards. let largeCircleOffset: CGPoint - /// The transform to be applied to the bezier path. + /// The transform to be applied to the entire bezier path. let transform: CGAffineTransform } @@ -150,7 +155,7 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { y: height) // Draw line to small-circle underneath and right to `rightNotchPoint`. - bezierPath.addLineTo(x: rightNotchPoint + bottomPathSmallCircleRadius + height, + bezierPath.addLineTo(x: height + rightNotchPoint + bottomPathSmallCircleRadius, y: height) // Draw the small circle right to the `rightNotchPoint`. @@ -162,7 +167,10 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { clockwise: false) // Draw the large circle left to the `rightNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: height + rightNotchPoint - notchConfig.largeCircleRadius - notchConfig.largeCircleOffset.x, + // + // We explicitly ignore the horizontal offset (`notchConfig.largeCircleOffset.x`) here, to have the paths of the + // small- and large-circles end/begin on the same point on the x-axis. + bezierPath.addArc(withCenter: CGPoint(x: height + rightNotchPoint - notchConfig.largeCircleRadius, y: height + smallCircleDiameter + notchConfig.largeCircleOffset.y), radius: notchConfig.largeCircleRadius, startAngle: 0, @@ -170,11 +178,17 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { clockwise: true) // Draw line to large-circle underneath and right to `leftNotchPoint` - bezierPath.addLineTo(x: height + leftNotchPoint + notchConfig.largeCircleRadius - notchConfig.largeCircleOffset.x, + // + // We explicitly ignore the horizontal offset (`notchConfig.largeCircleOffset.x`) here, to have the paths of the + // small- and large-circles end/begin on the same point on the x-axis. + bezierPath.addLineTo(x: height + leftNotchPoint + notchConfig.largeCircleRadius, y: height + smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.largeCircleOffset.y) // Draw the large circle right to the `leftNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - height + notchConfig.largeCircleRadius + notchConfig.largeCircleOffset.x, + // + // We explicitly ignore the horizontal offset (`notchConfig.largeCircleOffset.x`) here, to have the paths of the + // small- and large-circles end/begin on the same point on the x-axis. + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - height + notchConfig.largeCircleRadius, y: height + smallCircleDiameter + notchConfig.largeCircleOffset.y), radius: notchConfig.largeCircleRadius, startAngle: CGFloat.pi / 2, From 1f00f1d61f7aeb6197936d5647b4a24d645f67d1 Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Fri, 11 Mar 2022 15:05:51 +0100 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=93=9D=20::=20Update=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/iphone-x-screen-demystified.svg | 125 ++++++++++++++++++ .../NotchGradientLoadingBarController.swift | 3 +- 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 Assets/iphone-x-screen-demystified.svg diff --git a/Assets/iphone-x-screen-demystified.svg b/Assets/iphone-x-screen-demystified.svg new file mode 100644 index 0000000..4f007e9 --- /dev/null +++ b/Assets/iphone-x-screen-demystified.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 375 pt + + + + + + + 83 pt + + + + + + + 83 pt + + + + + + + 209 pt + + + + + + + 30 pt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 40 pt radius + + 6 pt radius + + 20 pt radius + + + + + + + + + + + + + + + + + + + + + + Source: https://www.paintcodeapp.com/news/iphone-x-screen-demystified + + \ No newline at end of file diff --git a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift index 43dfac1..dc47ce4 100644 --- a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift +++ b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift @@ -91,7 +91,8 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { let rightNotchPoint = (screenWidth + notchConfig.notchWidth) / 2 // The center point of the large circles lays at the bottom of the small circles. - // See graphic https://www.paintcodeapp.com/news/iphone-x-screen-demystified for further details. + // Please have a look at the graphic `Assets/iphone-x-screen-demystified.svg` or the entire article at + // https://www.paintcodeapp.com/news/iphone-x-screen-demystified for further details on the notch layout. let smallCircleDiameter: CGFloat = 2 * notchConfig.smallCircleRadius // Reducing the height here a little in order to match the "basic" gradient loading bar. From 9382248471339af62461aac6e1445bcd7710eac6 Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Fri, 11 Mar 2022 15:25:20 +0100 Subject: [PATCH 7/8] =?UTF-8?q?=E2=9C=85=20::=20Fix=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...NotchGradientLoadingBarViewModelTestCase.swift | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Example/Tests/ViewModel/NotchGradientLoadingBarViewModelTestCase.swift b/Example/Tests/ViewModel/NotchGradientLoadingBarViewModelTestCase.swift index dfb6a02..ac3b2ce 100644 --- a/Example/Tests/ViewModel/NotchGradientLoadingBarViewModelTestCase.swift +++ b/Example/Tests/ViewModel/NotchGradientLoadingBarViewModelTestCase.swift @@ -13,7 +13,7 @@ import XCTest class NotchGradientLoadingBarViewModelTestCase: XCTestCase { func testInitializerShouldSetSafeAreaDeviceToIPhoneX() { // Given - let deviceIdentifiers = ["iPhone10,3", "iPhone10,6", "iPhone11,2", "iPhone11,4", "iPhone11,6", "iPhone11,8"] + let deviceIdentifiers = ["iPhone10,3", "iPhone10,6", "iPhone11,2", "iPhone11,4", "iPhone11,6"] deviceIdentifiers.forEach { deviceIdentifier in // When @@ -24,6 +24,19 @@ class NotchGradientLoadingBarViewModelTestCase: XCTestCase { } } + func testInitializerShouldSetSafeAreaDeviceToIPhoneXR() { + // Given + let deviceIdentifiers = ["iPhone11,8"] + deviceIdentifiers.forEach { deviceIdentifier in + + // When + let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier) + + // Then + XCTAssertEqual(viewModel.safeAreaDevice, .iPhoneXR) + } + } + func testInitializerShouldSetSafeAreaDeviceToIPhone11() { // Given let deviceIdentifiers = ["iPhone12,1", "iPhone12,3", "iPhone12,5"] From cafd394cb7a688c80e8c3196f1fc61f19bb00880 Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Wed, 16 Mar 2022 17:30:49 +0100 Subject: [PATCH 8/8] =?UTF-8?q?=F0=9F=94=96=20::=20Bump=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 ++++++- Example/Podfile.lock | 6 +++--- .../Pods/Local Podspecs/GradientLoadingBar.podspec.json | 4 ++-- Example/Pods/Manifest.lock | 6 +++--- .../GradientLoadingBar/GradientLoadingBar-Info.plist | 2 +- GradientLoadingBar.podspec | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de39f6b..fc82781 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [Unreleased] +## [2.2.4] - 2022-16-03 +### Fixed + - Fixed incorrect layout on `NotchGradientLoadingBar` when using iPhone XR + ## [2.2.3] - 2021-29-12 ### Fixed - Fixed incorrect layout on `NotchGradientLoadingBar` when using an increased height ([#026], thanks to [alinfarcas12](https://github.com/alinfarcas12)) @@ -159,7 +163,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - Initial release -[Unreleased]: https://github.com/fxm90/GradientLoadingBar/compare/2.2.3...master +[Unreleased]: https://github.com/fxm90/GradientLoadingBar/compare/2.2.4...master +[2.2.2]: https://github.com/fxm90/GradientLoadingBar/compare/2.2.3...2.2.4 [2.2.2]: https://github.com/fxm90/GradientLoadingBar/compare/2.2.2...2.2.3 [2.2.2]: https://github.com/fxm90/GradientLoadingBar/compare/2.2.1...2.2.2 [2.2.1]: https://github.com/fxm90/GradientLoadingBar/compare/2.2.0...2.2.1 diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 72c5129..07f199c 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - GradientLoadingBar (2.2.3): + - GradientLoadingBar (2.2.4): - LightweightObservable (~> 2.1) - LightweightObservable (2.1.2) - SnapshotTesting (1.9.0) @@ -33,7 +33,7 @@ CHECKOUT OPTIONS: :git: https://github.com/fxm90/SwiftConfigurationFiles.git SPEC CHECKSUMS: - GradientLoadingBar: 157bd321c74e6bd0b0d87de735336060011393ab + GradientLoadingBar: 8972571e271c2da98f84a97de08f143c66df1894 LightweightObservable: c5ac85423a5edbed9a920b4d5c7b8f94ab3688c4 SnapshotTesting: 6141c48b6aa76ead61431ca665c14ab9a066c53b SwiftConfigurationFiles: 1cf2228a911ebed9f42f8dec077bb634f04ca6c8 @@ -42,4 +42,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 36b90780cb508f9eaca4f0ac59660e3e748de601 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/Example/Pods/Local Podspecs/GradientLoadingBar.podspec.json b/Example/Pods/Local Podspecs/GradientLoadingBar.podspec.json index 32f82ac..0927008 100644 --- a/Example/Pods/Local Podspecs/GradientLoadingBar.podspec.json +++ b/Example/Pods/Local Podspecs/GradientLoadingBar.podspec.json @@ -1,6 +1,6 @@ { "name": "GradientLoadingBar", - "version": "2.2.3", + "version": "2.2.4", "summary": "A customizable animated gradient loading bar.", "description": "A customizable animated gradient loading bar.\nInspired by https://codepen.io/marcobiedermann/pen/LExXWW", "homepage": "https://github.com/fxm90/GradientLoadingBar", @@ -14,7 +14,7 @@ }, "source": { "git": "https://github.com/fxm90/GradientLoadingBar.git", - "tag": "2.2.3" + "tag": "2.2.4" }, "swift_versions": "5.1", "platforms": { diff --git a/Example/Pods/Manifest.lock b/Example/Pods/Manifest.lock index 72c5129..07f199c 100644 --- a/Example/Pods/Manifest.lock +++ b/Example/Pods/Manifest.lock @@ -1,5 +1,5 @@ PODS: - - GradientLoadingBar (2.2.3): + - GradientLoadingBar (2.2.4): - LightweightObservable (~> 2.1) - LightweightObservable (2.1.2) - SnapshotTesting (1.9.0) @@ -33,7 +33,7 @@ CHECKOUT OPTIONS: :git: https://github.com/fxm90/SwiftConfigurationFiles.git SPEC CHECKSUMS: - GradientLoadingBar: 157bd321c74e6bd0b0d87de735336060011393ab + GradientLoadingBar: 8972571e271c2da98f84a97de08f143c66df1894 LightweightObservable: c5ac85423a5edbed9a920b4d5c7b8f94ab3688c4 SnapshotTesting: 6141c48b6aa76ead61431ca665c14ab9a066c53b SwiftConfigurationFiles: 1cf2228a911ebed9f42f8dec077bb634f04ca6c8 @@ -42,4 +42,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 36b90780cb508f9eaca4f0ac59660e3e748de601 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/Example/Pods/Target Support Files/GradientLoadingBar/GradientLoadingBar-Info.plist b/Example/Pods/Target Support Files/GradientLoadingBar/GradientLoadingBar-Info.plist index 086f7e6..bb11c61 100644 --- a/Example/Pods/Target Support Files/GradientLoadingBar/GradientLoadingBar-Info.plist +++ b/Example/Pods/Target Support Files/GradientLoadingBar/GradientLoadingBar-Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.2.3 + 2.2.4 CFBundleSignature ???? CFBundleVersion diff --git a/GradientLoadingBar.podspec b/GradientLoadingBar.podspec index 598e5b3..ad1e087 100644 --- a/GradientLoadingBar.podspec +++ b/GradientLoadingBar.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'GradientLoadingBar' - s.version = '2.2.3' + s.version = '2.2.4' s.summary = 'A customizable animated gradient loading bar.' # This description is used to generate tags and improve search results.