From 1eb5f68bf60820dc6c3d99f72ae21ab028637327 Mon Sep 17 00:00:00 2001 From: Maxim Makhun Date: Tue, 6 Sep 2022 16:06:59 -0700 Subject: [PATCH] Improve FloatingButton styling by removing shadow and introducing styling that is similar to other UI components. --- Example/ViewController.swift | 3 ++ .../MapboxNavigation/CameraController.swift | 19 +++++++--- Sources/MapboxNavigation/DayStyle.swift | 4 +- Sources/MapboxNavigation/FloatingButton.swift | 24 +++++++++--- .../InstructionsCardViewController.swift | 3 +- Sources/MapboxNavigation/NavigationView.swift | 14 +------ .../NavigationViewController.swift | 37 +++++++++++++++++-- Sources/MapboxNavigation/NightStyle.swift | 1 + .../OrnamentsController.swift | 21 +++++++---- Sources/MapboxNavigation/ReportButton.swift | 3 +- Sources/MapboxNavigation/Style.swift | 8 ++++ Sources/MapboxNavigation/UIImage.swift | 16 ++++++++ Sources/MapboxNavigation/UIView.swift | 7 ---- .../NavigationViewControllerTests.swift | 6 +-- 14 files changed, 119 insertions(+), 47 deletions(-) diff --git a/Example/ViewController.swift b/Example/ViewController.swift index 6dc92d5c91..d883c7ffc1 100644 --- a/Example/ViewController.swift +++ b/Example/ViewController.swift @@ -642,6 +642,7 @@ class ViewController: UIViewController { // Hide `WayNameView` and `FloatingStackView` to smoothly present them. navigationViewController.navigationView.wayNameView.alpha = 0.0 navigationViewController.navigationView.floatingStackView.alpha = 0.0 + navigationViewController.navigationView.speedLimitView.alpha = 0.0 present(navigationViewController, animated: animated) { completion?() @@ -655,6 +656,7 @@ class ViewController: UIViewController { animations: { navigationViewController.navigationView.wayNameView.alpha = 1.0 navigationViewController.navigationView.floatingStackView.alpha = 1.0 + navigationViewController.navigationView.speedLimitView.alpha = 1.0 }) navigationViewController.navigationView.topBannerContainerView.show(duration: 1.0) } @@ -674,6 +676,7 @@ class ViewController: UIViewController { animations: { activeNavigationViewController.navigationView.wayNameView.alpha = 0.0 activeNavigationViewController.navigationView.floatingStackView.alpha = 0.0 + activeNavigationViewController.navigationView.speedLimitView.alpha = 0.0 }, completion: { _ in activeNavigationViewController.dismiss(animated: animated) { diff --git a/Sources/MapboxNavigation/CameraController.swift b/Sources/MapboxNavigation/CameraController.swift index 764f1b1eb7..ef5bc0d117 100644 --- a/Sources/MapboxNavigation/CameraController.swift +++ b/Sources/MapboxNavigation/CameraController.swift @@ -105,20 +105,23 @@ class CameraController: NavigationComponent, NavigationComponentDelegate { } @objc func navigationCameraStateDidChange(_ notification: Notification) { - guard let navigationCameraState = notification.userInfo?[NavigationCamera.NotificationUserInfoKey.state] as? NavigationCameraState else { return } + guard let navigationViewController = navigationViewData.containerViewController as? NavigationViewController, + let navigationCameraState = notification.userInfo?[NavigationCamera.NotificationUserInfoKey.state] as? NavigationCameraState else { + return + } updateNavigationCameraViewport() switch navigationCameraState { case .transitionToFollowing, .following: - navigationViewData.navigationView.overviewButton.isHidden = false + navigationViewController.overviewButton.isHidden = false navigationViewData.navigationView.resumeButton.isHidden = true if let _ = navigationViewData.navigationView.wayNameView.text?.nonEmptyString { navigationViewData.navigationView.wayNameView.containerView.isHidden = false } break case .idle, .transitionToOverview, .overview: - navigationViewData.navigationView.overviewButton.isHidden = true + navigationViewController.overviewButton.isHidden = true navigationViewData.navigationView.resumeButton.isHidden = false navigationViewData.navigationView.wayNameView.containerView.isHidden = true break @@ -165,8 +168,14 @@ class CameraController: NavigationComponent, NavigationComponentDelegate { // MARK: NavigationComponentDelegate Implementation func navigationViewDidLoad(_: UIView) { - navigationViewData.navigationView.overviewButton.addTarget(self, action: #selector(overview(_:)), for: .touchUpInside) - navigationViewData.navigationView.resumeButton.addTarget(self, action: #selector(recenter(_:)), for: .touchUpInside) + let navigationViewController = navigationViewData.containerViewController as? NavigationViewController + navigationViewController?.overviewButton.addTarget(self, + action: #selector(overview(_:)), + for: .touchUpInside) + + navigationViewData.navigationView.resumeButton.addTarget(self, + action: #selector(recenter(_:)), + for: .touchUpInside) navigationMapView.userLocationStyle = .courseView() navigationViewData.navigationView.resumeButton.isHidden = true diff --git a/Sources/MapboxNavigation/DayStyle.swift b/Sources/MapboxNavigation/DayStyle.swift index f57b381cb2..709c85b17d 100644 --- a/Sources/MapboxNavigation/DayStyle.swift +++ b/Sources/MapboxNavigation/DayStyle.swift @@ -247,6 +247,8 @@ open class DayStyle: Style { FloatingButton.appearance(for: traitCollection).backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) FloatingButton.appearance(for: traitCollection).tintColor = tintColor + FloatingButton.appearance(for: traitCollection).borderWidth = Style.defaultBorderWidth + FloatingButton.appearance(for: traitCollection).borderColor = #colorLiteral(red: 0.737254902, green: 0.7960784314, blue: 0.8705882353, alpha: 1) DistanceRemainingLabel.appearance(for: traitCollection).normalFont = UIFont.systemFont(ofSize: 18.0, weight: .medium).adjustedFont DistanceRemainingLabel.appearance(for: traitCollection).normalTextColor = #colorLiteral(red: 0.431372549, green: 0.431372549, blue: 0.431372549, alpha: 1) @@ -262,7 +264,7 @@ open class DayStyle: Style { ResumeButton.appearance(for: traitCollection).backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) ResumeButton.appearance(for: traitCollection).tintColor = .defaultPrimaryText ResumeButton.appearance(for: traitCollection).borderColor = #colorLiteral(red: 0.737254902, green: 0.7960784314, blue: 0.8705882353, alpha: 1) - ResumeButton.appearance(for: traitCollection).borderWidth = 1 / UIScreen.main.scale + ResumeButton.appearance(for: traitCollection).borderWidth = Style.defaultBorderWidth ResumeButton.appearance(for: traitCollection).cornerRadius = 5.0 NextBannerView.appearance(for: traitCollection).backgroundColor = #colorLiteral(red: 0.9675388083, green: 0.9675388083, blue: 0.9675388083, alpha: 1) diff --git a/Sources/MapboxNavigation/FloatingButton.swift b/Sources/MapboxNavigation/FloatingButton.swift index 19c8f32406..44b4bb2d28 100644 --- a/Sources/MapboxNavigation/FloatingButton.swift +++ b/Sources/MapboxNavigation/FloatingButton.swift @@ -44,16 +44,30 @@ open class FloatingButton: Button { - parameter image: The `UIImage` of this button. - parameter selectedImage: The `UIImage` of this button when selected. - parameter size: The size of this button, or `FloatingButton.buttonSize` if this argument is not specified. + - parameter type: `UIButton` type. Defaults to `.custom`. + - parameter cornerRadius: Corner radius of the button. + + - returns: `FloatingButton` instance. */ public class func rounded(image: UIImage? = nil, selectedImage: UIImage? = nil, - size: CGSize = FloatingButton.buttonSize) -> T { - let button = T.init(type: .custom) + size: CGSize = FloatingButton.buttonSize, + type: UIButton.ButtonType = .custom, + cornerRadius: CGFloat = FloatingButton.buttonSize.width / 2.0) -> T { + let button = T.init(type: type) button.translatesAutoresizingMaskIntoConstraints = false button.constrainedSize = size - button.setImage(image, for: .normal) - if let selected = selectedImage { button.setImage(selected, for: .selected) } - button.applyDefaultCornerRadiusShadow(cornerRadius: size.width / 2) + button.layer.cornerRadius = cornerRadius + button.imageView?.contentMode = .scaleAspectFit + + if let image = image { + button.setImage(image, for: .normal) + } + + if let selectedImage = selectedImage { + button.setImage(selectedImage, for: .selected) + } + return button } } diff --git a/Sources/MapboxNavigation/InstructionsCardViewController.swift b/Sources/MapboxNavigation/InstructionsCardViewController.swift index ca0ee382d5..10afadf64c 100644 --- a/Sources/MapboxNavigation/InstructionsCardViewController.swift +++ b/Sources/MapboxNavigation/InstructionsCardViewController.swift @@ -90,7 +90,8 @@ open class InstructionsCardViewController: UIViewController { lazy var junctionView: JunctionView = { let view: JunctionView = .forAutoLayout() view.isHidden = true - view.applyDefaultCornerRadiusShadow(cornerRadius: 4, shadowOpacity: 0.4) + view.layer.cornerRadius = Style.defaultCornerRadius + return view }() diff --git a/Sources/MapboxNavigation/NavigationView.swift b/Sources/MapboxNavigation/NavigationView.swift index c15164b1cd..43cb1929fe 100644 --- a/Sources/MapboxNavigation/NavigationView.swift +++ b/Sources/MapboxNavigation/NavigationView.swift @@ -44,13 +44,6 @@ open class NavigationView: UIView { static let buttonSpacing: CGFloat = 8.0 } - private enum Images { - static let overview = UIImage(named: "overview", in: .mapboxNavigation, compatibleWith: nil)!.withRenderingMode(.alwaysTemplate) - static let volumeUp = UIImage(named: "volume_up", in: .mapboxNavigation, compatibleWith: nil)!.withRenderingMode(.alwaysTemplate) - static let volumeOff = UIImage(named: "volume_off", in: .mapboxNavigation, compatibleWith: nil)!.withRenderingMode(.alwaysTemplate) - static let feedback = UIImage(named: "feedback", in: .mapboxNavigation, compatibleWith: nil)!.withRenderingMode(.alwaysTemplate) - } - var compactConstraints = [NSLayoutConstraint]() var regularConstraints = [NSLayoutConstraint]() @@ -125,10 +118,6 @@ open class NavigationView: UIView { return stackView }() - lazy var overviewButton = FloatingButton.rounded(image: Images.overview) - lazy var muteButton = FloatingButton.rounded(image: Images.volumeUp, selectedImage: Images.volumeOff) - lazy var reportButton = FloatingButton.rounded(image: Images.feedback) - var floatingButtonsPosition: MapOrnamentPosition = .topTrailing { didSet { setupConstraints() @@ -143,7 +132,7 @@ open class NavigationView: UIView { } } - lazy var resumeButton: ResumeButton = .forAutoLayout() + lazy var resumeButton: ResumeButton = .forAutoLayout(hidden: true) var wayNameViewLayoutGuide: UILayoutGuide? { didSet { @@ -226,7 +215,6 @@ open class NavigationView: UIView { func commonInit() { DayStyle().apply() - floatingButtons = [overviewButton, muteButton, reportButton] setupViews() setupConstraints() } diff --git a/Sources/MapboxNavigation/NavigationViewController.swift b/Sources/MapboxNavigation/NavigationViewController.swift index 57149dbcc2..1f58c06b1b 100644 --- a/Sources/MapboxNavigation/NavigationViewController.swift +++ b/Sources/MapboxNavigation/NavigationViewController.swift @@ -235,6 +235,28 @@ open class NavigationViewController: UIViewController, NavigationStatusPresenter navigationService.router } + lazy var overviewButton: FloatingButton = { + let floatingButton = FloatingButton.rounded(image: .overview) + floatingButton.borderWidth = Style.defaultBorderWidth + + return floatingButton + }() + + lazy var muteButton: FloatingButton = { + let floatingButton = FloatingButton.rounded(image: .volumeUp, + selectedImage: .volumeOff) + floatingButton.borderWidth = Style.defaultBorderWidth + + return floatingButton + }() + + lazy var reportButton: FloatingButton = { + let floatingButton = FloatingButton.rounded(image: .feedback) + floatingButton.borderWidth = Style.defaultBorderWidth + + return floatingButton + }() + func setupNavigationService() { guard let routeResponse = _routeResponse, let routeIndex = _routeIndex, @@ -365,7 +387,16 @@ open class NavigationViewController: UIViewController, NavigationStatusPresenter open override func loadView() { let frame = parent?.view.bounds ?? UIScreen.main.bounds - view = NavigationView(delegate: self, frame: frame, tileStoreLocation: mapTileStore, navigationMapView: self.navigationOptions?.navigationMapView) + view = NavigationView(delegate: self, + frame: frame, + tileStoreLocation: mapTileStore, + navigationMapView: self.navigationOptions?.navigationMapView) + + navigationView.floatingButtons = [ + overviewButton, + muteButton, + reportButton + ] } /** @@ -503,7 +534,7 @@ open class NavigationViewController: UIViewController, NavigationStatusPresenter public var showsReportFeedback: Bool = true { didSet { loadViewIfNeeded() - ornamentsController?.reportButton.isHidden = !showsReportFeedback + reportButton.isHidden = !showsReportFeedback showsEndOfRouteFeedback = showsReportFeedback } } @@ -603,7 +634,7 @@ open class NavigationViewController: UIViewController, NavigationStatusPresenter subviewInits.removeAll() arrivalController?.destination = route?.legs.last?.destination - ornamentsController?.reportButton.isHidden = !showsReportFeedback + reportButton.isHidden = !showsReportFeedback } func addTopBanner(_ navigationOptions: NavigationOptions?) -> ContainerViewController { diff --git a/Sources/MapboxNavigation/NightStyle.swift b/Sources/MapboxNavigation/NightStyle.swift index a85ba56796..101729b8f3 100644 --- a/Sources/MapboxNavigation/NightStyle.swift +++ b/Sources/MapboxNavigation/NightStyle.swift @@ -26,6 +26,7 @@ open class NightStyle: DayStyle { FloatingButton.appearance(for: traitCollection).backgroundColor = .defaultDarkAppearanceBackgroundColor FloatingButton.appearance(for: traitCollection).tintColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1) + FloatingButton.appearance(for: traitCollection).borderColor = #colorLiteral(red: 0.3764705882, green: 0.4901960784, blue: 0.6117647059, alpha: 0.796599912) InstructionsCardContainerView.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsCardCell.self]).customBackgroundColor = .defaultDarkAppearanceBackgroundColor InstructionsCardContainerView.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsCardCell.self]).separatorColor = #colorLiteral(red: 0.3764705882, green: 0.4901960784, blue: 0.6117647059, alpha: 0.796599912) diff --git a/Sources/MapboxNavigation/OrnamentsController.swift b/Sources/MapboxNavigation/OrnamentsController.swift index 27046943ec..442f9b8898 100644 --- a/Sources/MapboxNavigation/OrnamentsController.swift +++ b/Sources/MapboxNavigation/OrnamentsController.swift @@ -118,10 +118,6 @@ class OrnamentsController: NavigationComponent, NavigationComponentDelegate { } } - var reportButton: FloatingButton { - return navigationView.reportButton - } - @objc func toggleMute(_ sender: UIButton) { sender.isSelected = !sender.isSelected @@ -211,13 +207,24 @@ class OrnamentsController: NavigationComponent, NavigationComponentDelegate { // MARK: NavigationComponentDelegate implementation func navigationViewDidLoad(_: UIView) { - navigationView.muteButton.addTarget(self, action: #selector(toggleMute(_:)), for: .touchUpInside) - navigationView.reportButton.addTarget(self, action: #selector(feedback(_:)), for: .touchUpInside) + guard let navigationViewController = navigationViewData.containerViewController as? NavigationViewController else { + return + } + + navigationViewController.muteButton.addTarget(self, + action: #selector(toggleMute(_:)), + for: .touchUpInside) + + navigationViewController.reportButton.addTarget(self, + action: #selector(feedback(_:)), + for: .touchUpInside) } func navigationViewWillAppear(_: Bool) { resumeNotifications() - navigationView.muteButton.isSelected = NavigationSettings.shared.voiceMuted + + let navigationViewController = navigationViewData.containerViewController as? NavigationViewController + navigationViewController?.muteButton.isSelected = NavigationSettings.shared.voiceMuted } func navigationViewDidDisappear(_: Bool) { diff --git a/Sources/MapboxNavigation/ReportButton.swift b/Sources/MapboxNavigation/ReportButton.swift index 4ddad41e55..6a95e0f1c2 100644 --- a/Sources/MapboxNavigation/ReportButton.swift +++ b/Sources/MapboxNavigation/ReportButton.swift @@ -6,7 +6,6 @@ import UIKit public class ReportButton: Button { static let defaultInsets: UIEdgeInsets = 10.0 - static let defaultCornerRadius: CGFloat = 4.0 public required init?(coder decoder: NSCoder) { super.init(coder: decoder) @@ -22,6 +21,6 @@ public class ReportButton: Button { private func commonInit() { contentEdgeInsets = ReportButton.defaultInsets - applyDefaultCornerRadiusShadow(cornerRadius: ReportButton.defaultCornerRadius) + layer.cornerRadius = Style.defaultCornerRadius } } diff --git a/Sources/MapboxNavigation/Style.swift b/Sources/MapboxNavigation/Style.swift index b971294c90..a4419f8aa1 100644 --- a/Sources/MapboxNavigation/Style.swift +++ b/Sources/MapboxNavigation/Style.swift @@ -49,6 +49,14 @@ open class Style: NSObject { UITraitCollection(userInterfaceIdiom: .pad), ]) + class var defaultBorderWidth: CGFloat { + 1 / UIScreen.main.scale + } + + class var defaultCornerRadius: CGFloat { + 10.0 + } + /** Applies the style for all changed properties. */ diff --git a/Sources/MapboxNavigation/UIImage.swift b/Sources/MapboxNavigation/UIImage.swift index 1d526a3627..89910375af 100644 --- a/Sources/MapboxNavigation/UIImage.swift +++ b/Sources/MapboxNavigation/UIImage.swift @@ -2,6 +2,22 @@ import UIKit extension UIImage { + static let overview = UIImage(named: "overview", + in: .mapboxNavigation, + compatibleWith: nil)!.withRenderingMode(.alwaysTemplate) + + static let volumeUp = UIImage(named: "volume_up", + in: .mapboxNavigation, + compatibleWith: nil)!.withRenderingMode(.alwaysTemplate) + + static let volumeOff = UIImage(named: "volume_off", + in: .mapboxNavigation, + compatibleWith: nil)!.withRenderingMode(.alwaysTemplate) + + static let feedback = UIImage(named: "feedback", + in: .mapboxNavigation, + compatibleWith: nil)!.withRenderingMode(.alwaysTemplate) + convenience init?(color: UIColor, size: CGSize = CGSize(width: 1.0, height: 1.0)) { let rect = CGRect(origin: .zero, size: size) UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0) diff --git a/Sources/MapboxNavigation/UIView.swift b/Sources/MapboxNavigation/UIView.swift index 63bba11491..7831d7a6d3 100644 --- a/Sources/MapboxNavigation/UIView.swift +++ b/Sources/MapboxNavigation/UIView.swift @@ -48,13 +48,6 @@ extension UIView { // MARK: Layer Styling - func applyDefaultCornerRadiusShadow(cornerRadius: CGFloat? = 4, shadowOpacity: CGFloat? = 0.1) { - layer.cornerRadius = cornerRadius! - layer.shadowOffset = CGSize(width: 0, height: 0) - layer.shadowRadius = 4 - layer.shadowOpacity = Float(shadowOpacity!) - } - func applyGradient(colors: [UIColor], locations: [NSNumber]? = nil) { let gradient: CAGradientLayer = CAGradientLayer() gradient.frame = self.bounds diff --git a/Tests/MapboxNavigationTests/NavigationViewControllerTests.swift b/Tests/MapboxNavigationTests/NavigationViewControllerTests.swift index 44510e29d0..a0cd330d08 100644 --- a/Tests/MapboxNavigationTests/NavigationViewControllerTests.swift +++ b/Tests/MapboxNavigationTests/NavigationViewControllerTests.swift @@ -488,13 +488,13 @@ class NavigationViewControllerTests: TestCase { 3, "There should be three floating buttons by default.") XCTAssertEqual(navigationViewController.floatingButtons?[0], - navigationViewController.navigationView.overviewButton, + navigationViewController.overviewButton, "Unexpected floating button.") XCTAssertEqual(navigationViewController.floatingButtons?[1], - navigationViewController.navigationView.muteButton, + navigationViewController.muteButton, "Unexpected floating button.") XCTAssertEqual(navigationViewController.floatingButtons?[2], - navigationViewController.navigationView.reportButton, + navigationViewController.reportButton, "Unexpected floating button.") navigationViewController.floatingButtons = []