From 5aa2f5d5ba0ebf7908a1ea1c339599130bcceea1 Mon Sep 17 00:00:00 2001 From: Felix M Date: Wed, 7 Sep 2022 18:15:15 +0200 Subject: [PATCH] Enhance BezierPath of NotchGradientLoadingBar (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ♻️ :: Enhance bezierpath * ⬆️ :: Update fastlane plugin * ⬆️ :: Update dev-dependencies * ✅ :: Adapt snapshot tests * Revert "⬆️ :: Update dev-dependencies" This reverts commit 45328c27ea84f22ba4c1edd9712abd2d1ba9f8aa. --- ...st_notchGradientLoadingBarController.1.png | Bin 77017 -> 76489 bytes Example/Gemfile.lock | 4 +- .../NotchGradientLoadingBarController.swift | 164 +++++++++--------- 3 files changed, 81 insertions(+), 87 deletions(-) diff --git a/Example/ExampleSnapshotTests/NotchGradientLoadingBar/__Snapshots__/NotchGradientLoadingBarControllerTestCase/test_notchGradientLoadingBarController.1.png b/Example/ExampleSnapshotTests/NotchGradientLoadingBar/__Snapshots__/NotchGradientLoadingBarControllerTestCase/test_notchGradientLoadingBarController.1.png index 28f144c50ea45b40a9d9c92021cc0e314a39c679..2b2853f556125cea57bb92d8aa9c5dab1ed5f208 100644 GIT binary patch literal 76489 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%0AQl7- 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 F{{o=JeKG(5 literal 77017 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 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-swiftformat (0.2.0) + fastlane-plugin-swiftformat (0.3.0) ffi (1.15.5) fourflusher (2.3.1) fuzzy_match (2.0.4) @@ -283,4 +283,4 @@ DEPENDENCIES fastlane-plugin-swiftformat BUNDLED WITH - 2.3.8 + 2.3.18 diff --git a/GradientLoadingBar/Feature/NotchGradientLoadingBar/NotchGradientLoadingBarController.swift b/GradientLoadingBar/Feature/NotchGradientLoadingBar/NotchGradientLoadingBarController.swift index f3395fa..70f8f1c 100644 --- a/GradientLoadingBar/Feature/NotchGradientLoadingBar/NotchGradientLoadingBarController.swift +++ b/GradientLoadingBar/Feature/NotchGradientLoadingBar/NotchGradientLoadingBarController.swift @@ -8,31 +8,6 @@ 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 - - /// 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 entire bezier path. - let transform: CGAffineTransform -} - /// Type-alias for the controller to be more similar to the pod name. public typealias NotchGradientLoadingBar = NotchGradientLoadingBarController @@ -45,7 +20,7 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // MARK: - Public methods override open func setupConstraints(superview: UIView) { - guard let notchConfig = viewModel.safeAreaDevice.notchConfig else { + guard let notchConfig = NotchConfig(safeAreaDevice: viewModel.safeAreaDevice) else { // No special masking required for non safe area devices. super.setupConstraints(superview: superview) return @@ -72,12 +47,16 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // swiftlint:disable:next function_body_length private func notchBezierPath(for screenWidth: CGFloat, notchConfig: NotchConfig) -> UIBezierPath { // We always center the notch in the middle of the screen. + // + // 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. + // + // In the graphic the `leftNotchPoint` lays `83pt` from the left side of the device and + // the `rightNotchPoint` lays `83pt` from the right. 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. - // 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. @@ -101,20 +80,20 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { clockwise: true) // Draw the large circle right to the `leftNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint + notchConfig.largeCircleRadius + notchConfig.largeCircleOffset.x, - y: smallCircleDiameter + notchConfig.largeCircleOffset.y), + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint + notchConfig.largeCircleRadius, + y: smallCircleDiameter + notchConfig.largeCircleVerticalOffset), 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 - notchConfig.largeCircleOffset.x, - y: smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.largeCircleOffset.y) + bezierPath.addLineTo(x: rightNotchPoint - notchConfig.largeCircleRadius, + y: smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.largeCircleVerticalOffset) // Draw the large circle left to the `rightNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint - notchConfig.largeCircleRadius - notchConfig.largeCircleOffset.x, - y: smallCircleDiameter + notchConfig.largeCircleOffset.y), + bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint - notchConfig.largeCircleRadius, + y: smallCircleDiameter + notchConfig.largeCircleVerticalOffset), radius: notchConfig.largeCircleRadius, startAngle: CGFloat.pi / 2, endAngle: 0, @@ -132,59 +111,50 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { bezierPath.addLineTo(x: screenWidth, y: 0) // 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 = (notchConfig.smallCircleRadius / 3) * 2 + // + // For the circles on the way back we use the same center point as in the beginning but adapt the radius. + // See also: https://twitter.com/lilykonings/status/1567317037126680576?s=46&t=Cm2Q8BsqSY_nbCrZqGE08g // Draw line down. bezierPath.addLineTo(x: screenWidth, y: height) // Draw line to small-circle underneath and right to `rightNotchPoint`. - bezierPath.addLineTo(x: height + rightNotchPoint + bottomPathSmallCircleRadius, + bezierPath.addLineTo(x: height + rightNotchPoint + notchConfig.smallCircleRadius, y: height) // Draw the small circle right to the `rightNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: height + rightNotchPoint + bottomPathSmallCircleRadius, - y: height + bottomPathSmallCircleRadius), - radius: bottomPathSmallCircleRadius, + bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint + notchConfig.smallCircleRadius, + y: notchConfig.smallCircleRadius), + radius: notchConfig.smallCircleRadius - height, startAngle: CGFloat.pi + CGFloat.pi / 2, endAngle: CGFloat.pi, clockwise: false) // Draw the large circle left to the `rightNotchPoint`. - // - // 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, + bezierPath.addArc(withCenter: CGPoint(x: rightNotchPoint - notchConfig.largeCircleRadius, + y: smallCircleDiameter + notchConfig.largeCircleVerticalOffset), + radius: notchConfig.largeCircleRadius + height, startAngle: 0, endAngle: CGFloat.pi / 2, clockwise: true) // Draw line to large-circle underneath and right to `leftNotchPoint` - // - // 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) + y: height + smallCircleDiameter + notchConfig.largeCircleRadius + notchConfig.largeCircleVerticalOffset) // Draw the large circle right to the `leftNotchPoint`. - // - // 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, + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint + notchConfig.largeCircleRadius, + y: smallCircleDiameter + notchConfig.largeCircleVerticalOffset), + radius: notchConfig.largeCircleRadius + height, startAngle: CGFloat.pi / 2, endAngle: CGFloat.pi, clockwise: true) // Draw the small circle left to the `leftNotchPoint`. - bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - height - bottomPathSmallCircleRadius, - y: height + bottomPathSmallCircleRadius), - radius: bottomPathSmallCircleRadius, + bezierPath.addArc(withCenter: CGPoint(x: leftNotchPoint - notchConfig.smallCircleRadius, + y: notchConfig.smallCircleRadius), + radius: notchConfig.smallCircleRadius - height, startAngle: 0, endAngle: -CGFloat.pi / 2, clockwise: false) @@ -211,52 +181,76 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { } } -// MARK: - Helper +// MARK: - Supporting Types -private extension NotchGradientLoadingBarViewModel.SafeAreaDevice { - /// The notch specific configuration for the current device. - var notchConfig: NotchConfig? { - switch self { +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 + + /// Vertical offset for the center-point of the large circle: + /// - A positive value will move the large circles downwards. + /// - A negative offset will move them upwards. + let largeCircleVerticalOffset: CGFloat + + /// The transform to be applied to the entire bezier path. + let transform: CGAffineTransform +} + +private extension NotchConfig { + + /// Initializes the notch specific configuration for the current safe area device. + /// + /// - Note: We define this in an extension to keep the memberwise initializer. + init?(safeAreaDevice: NotchGradientLoadingBarViewModel.SafeAreaDevice) { + switch safeAreaDevice { case .unknown: return nil case .iPhoneX: /// The default configuration for the iPhone X and 11. /// Values are based on . - return NotchConfig(notchWidth: 208, - largeCircleRadius: 22.5, - largeCircleOffset: CGPoint(x: 0, y: -4.75), - transform: CGAffineTransform(translationX: 0.33, y: 0)) + self.init(notchWidth: 208, + largeCircleRadius: 22.5, + largeCircleVerticalOffset: -4.75, + transform: CGAffineTransform(translationX: 0.33, y: 0)) case .iPhoneXR, .iPhone11: - return NotchConfig(notchWidth: 232, - largeCircleRadius: 24, - largeCircleOffset: CGPoint(x: 0.5, y: -3.5), - transform: .identity) + self.init(notchWidth: 230.5, + largeCircleRadius: 24, + largeCircleVerticalOffset: -3.5, + transform: .identity) case .iPhone11Pro, .iPhone11ProMax: - return NotchConfig(notchWidth: 209.5, - largeCircleRadius: 21, - largeCircleOffset: CGPoint(x: 0, y: -3.5), - transform: .identity) + self.init(notchWidth: 209, + largeCircleRadius: 21, + largeCircleVerticalOffset: -3.5, + transform: .identity) case .iPhone12: - return NotchConfig(notchWidth: 209.5, - largeCircleRadius: 21, - largeCircleOffset: CGPoint(x: 0, y: -1.75), - transform: .identity) + self.init(notchWidth: 209.5, + largeCircleRadius: 21, + largeCircleVerticalOffset: -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, - largeCircleOffset: CGPoint(x: 0, y: -1), - transform: .identity) + self.init(notchWidth: 161, + largeCircleRadius: 22, + largeCircleVerticalOffset: -1, + transform: .identity) } } } +// MARK: - Helper + private extension UIBezierPath { // swiftlint:disable:next identifier_name