在全球范围内的梯度应用到导航条和处理方向变化

问题描述 投票:1回答:1

我需要在全球范围内应用渐变到我的状态和导航栏,以及有它正确地调整方向的变化。因为我想这是全球性的,我想用UIAppearance。出人意料的是,UIAppearance不会使这个非常容易。

它在肖像看起来很大,但坡度太高时,在景观,所以你不能看到整个事情:

Comparison of portrait and landscape gradient nav bar

这里是我的代码,这一点:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let navigationBarAppearance = UINavigationBar.appearance()
    navigationBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
    navigationBarAppearance.isTranslucent = false
    navigationBarAppearance.tintColor = UIColor.white

    let status_height = UIApplication.shared.statusBarFrame.size.height
    let gradientLayer = CAGradientLayer(frame: CGRect(x: 0, y: 0, width: 64, height: status_height + 44), colors: [UIColor.init(hex: "005382"), UIColor.init(hex: "00294B")])
    let layerImage = gradientLayer.createGradientImage()
    navigationBarAppearance.barTintColor = UIColor(patternImage: layerImage ?? UIImage())
}

和我使用这个扩展:

extension CAGradientLayer {
  convenience init(frame: CGRect, colors: [UIColor]) {
    self.init()
    self.frame = frame
    self.colors = []
    for color in colors {
      self.colors?.append(color.cgColor)
    }
    startPoint = CGPoint(x: 0, y: 0)
    endPoint = CGPoint(x: 0, y: 1)
  }

  func createGradientImage() -> UIImage? {

    var image: UIImage? = nil

    UIGraphicsBeginImageContext(bounds.size)

    if let context = UIGraphicsGetCurrentContext() {
      render(in: context)
      image = UIGraphicsGetImageFromCurrentImageContext()
    }

    UIGraphicsEndImageContext()

    return image
  } 
}

我知道我可以检查方向,然后相应地改变梯度但我需要做的每个视图控制器上,这样会破坏使用UIAppearance并能做到在一个地方的目的。

大部分的SO线程我发现提供了在视图控制器级别造顶栏的梯度溶液,但不是全局的水平。

编辑:我试过UITabBarController回答@Pan Surakami但我仍然有白色的导航栏:

enter image description here

这是我的故事板的设置:

enter image description here

和代码:

class MenuTabBarController: UITabBarController {
    var notificationsVM = NotificationsVModel()
    var hasNewAlerts: Bool = false

    override func viewDidLoad() {
      super.viewDidLoad()

      setTabs()

      styleUI()

      notificationsVM.fetchData { (success, newNotifications) in
            if success {
                self.hasNewAlerts = newNotifications.count > 0 ? true : false
                DispatchQueue.main.async {
                    if let tabBarItems = self.tabBar.items {
                        for (_, each) in tabBarItems.enumerated() {
                            if each.tag == 999 { //only update the alerts tabBarItem tag == '999'
                                self.updateAlertBadgeIcon(self.hasNewAlerts, each)
                            }
                        }
                    }
                }
            }
        }
    }

  fileprivate func setTabs() {
    let tab1 = GradientNavigationController(rootViewController: FeedViewController())
    let tab2 = GradientNavigationController(rootViewController: NotificationsTableViewController())
    let tab3 = GradientNavigationController(rootViewController: SearchViewController())
    let tab4 = GradientNavigationController(rootViewController: ComposeDiscussionViewController())
    UITabBarController().setViewControllers([tab1, tab2, tab3, tab4], animated: false)
  }

    func updateAlertBadgeIcon(_ hasAlerts: Bool, _ item: UITabBarItem) {
        if hasAlerts {
            item.image = UIImage(named: "alert-unselected-hasAlerts")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
            item.selectedImage = UIImage(named: "alert-selected-hasAlerts")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
        } else {
            hasNewAlerts = false
            item.image = UIImage(named: "alert-unselected-noAlerts")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
            item.selectedImage = UIImage(named: "alert-selected-noAlerts")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
        }
    }

    // UITabBarDelegate
    override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
        if item.tag == 999 { //alerts tabBarItem tag == '999'
            updateAlertBadgeIcon(hasNewAlerts, item)
        }
      if item.tag == 0 { //Feed Item clicked
        if let feedNav = children[0] as? UINavigationController, let feedVC = feedNav.viewControllers[0] as? FeedViewController {
          feedVC.tableView.reloadData()
        }

      }
    }

    func styleUI() {
        UITabBar.appearance().backgroundImage = UIImage.colorForNavBar(color:.lightGrey4)
        UITabBar.appearance().shadowImage = UIImage.colorForNavBar(color:.clear) 
        tabBar.layer.shadowOffset = CGSize.zero
        tabBar.layer.shadowRadius = 2.0
        tabBar.layer.shadowColor = UIColor.black.cgColor
        tabBar.layer.shadowOpacity = 0.30
        UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.grey2,
                                                          NSAttributedString.Key.font: UIFont(name: "AvenirNext-DemiBold", size: 12) as Any],
                                                         for: .normal)
        UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.darkSapphire,
                                                          NSAttributedString.Key.font: UIFont(name: "AvenirNext-DemiBold", size: 12) as Any],
                                                         for: .selected)
    }
}
ios swift uinavigationbar uistatusbar uiappearance
1个回答
0
投票

实现它的一种方式是继承UINavigationController

  1. 创建一个新的子类。
class GradientNavigationController: UINavigationController {}
  1. 覆盖traitCollectionDidChange方法。
class GradientNavigationController: UINavigationController {
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        let status_height = UIApplication.shared.statusBarFrame.size.height
        let gradientLayer = CAGradientLayer(frame: CGRect(x: 0, y: 0, width: 64, height: status_height + 44), colors: [[UIColor.init(hex: "005382"), UIColor.init(hex: "00294B")])
        let layerImage = gradientLayer.createGradientImage()
        self.navigationBar.barTintColor = UIColor(patternImage: layerImage ?? UIImage())
    }
}
  1. 使用这个子类,而不是UINavigationController的。要么改变对storiboards自定义子类或代码中使用它。

编辑:您UITabBarController是由故事板配置。所以setTabs()用这种方式有没有意义。它只是创造UITabBarController的另一个副本,然后删除它。我发现它只是为嵌入控制器的一个例子。

  1. 取出方法setTabs()
  2. 打开每个链接到你的标签的故事板。 (我看不出他们是如何实际配置它们背后的故事板的引用。)
  3. 确保初始控制器GradientNavigationController

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.