【问题标题】:Handling navigation bar background gradient in iPhone X在 iPhone X 中处理导航栏背景渐变
【发布时间】:2017-09-22 09:12:52
【问题描述】:

到目前为止,我以以下方式处理导航栏中的渐变_

let gradient = CAGradientLayer()
    let sizeLength = UIScreen.main.bounds.size.height * 2
    let defaultNavigationBarFrame = CGRect(x: 0, y: 0, width: sizeLength, height: 64)
    gradient.frame = defaultNavigationBarFrame
    gradient.colors = [UIColor(hex:"92CF1F").cgColor, UIColor(hex:"79AB1B").cgColor]

    UINavigationBar.appearance().setBackgroundImage(self.image(fromLayer: gradient), for: .default)
    UINavigationBar.appearance().tintColor = UIColor.white
    UINavigationBar.appearance().isTranslucent = false
    UINavigationBar.appearance().clipsToBounds = false

    if DeviceType.IS_IPAD{
        UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName : UIFont .systemFont(ofSize: 24, weight: UIFontWeightLight), NSForegroundColorAttributeName: UIColor.white]
    }
    else
    {
        UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName : UIFont .systemFont(ofSize: 20, weight: UIFontWeightLight), NSForegroundColorAttributeName: UIColor.white]
    }

    UISearchBar.appearance().backgroundColor = UIColor.clear

但现在在 iPhone X 中,由于“64”作为渐变导航栏的高度,我遇到了如下问题_

请提出一个可以在每种情况下动态使用的修复方法。

【问题讨论】:

    标签: ios swift iphone-x


    【解决方案1】:

    使用 Alisson Barauna 对您的问题的回答,我设法通过将我的 UINavigationBar 扩展更新为如下所示来解决此问题:

    extension UINavigationBar {
    
    @objc func setGradientBackground(colors: [UIColor]) {
    
        var updatedFrame = bounds
    
        if UIDevice().userInterfaceIdiom == .phone {
            if UIScreen.main.nativeBounds.height == 2436{
                updatedFrame.size.height += 44
            } else {
                updatedFrame.size.height += 20
            }
        }
    
        let gradientLayer = CAGradientLayer(frame: updatedFrame, colors: colors)
        setBackgroundImage(gradientLayer.createGradientImage(), for: UIBarMetrics.default)
    }
    

    如果程序检测到正在使用 iPhone X(因为屏幕高度为 2436),那么高度只会设置为更大的 iPhone X 尺寸 (44)。

    【讨论】:

    • 你可以使用updatedFrame.size.height += navigationBar.frame.maxY,这样你就不用检查设备了。
    【解决方案2】:

    我已经通过屏幕高度检查了 iPhone X 模式,然后我更改了生成的渐变图像以填充导航栏。 我认为这不是最好的解决方法,但现在可以正常工作。

    class func checkiPhoneModel() -> String {
        if UIDevice().userInterfaceIdiom == .phone {
            switch UIScreen.main.nativeBounds.height {
            case 1136:
                return "5, 5s, 5c, se"
            case 1334:
                return "6, 6s, 7"
            case 2208:
                return "6+, 6S+, 7+"
            case 2436:
                return "X"
            default:
                return "unknown"
            }
        }
        return ""
    }
    

    然后你可以为 UINavigationBar 创建一个扩展,添加一个改变渐变图像颜色的方法:

    extension UINavigationBar {
    
        func setGradientBackground(colors: [UIColor]) {
    
            var size:CGFloat
    
            if Reachability.checkiPhoneModel() == "X" {
              size = 44
            }
            else {
                size = 20
            }
    
            var updatedFrame = bounds
            updatedFrame.size.height += size
            let gradientLayer = CAGradientLayer(frame: updatedFrame, colors: colors)
    
            setBackgroundImage(gradientLayer.creatGradientImage(), for: UIBarMetrics.default)
        }
    }
    

    当 iPhone X 时 size var 设置为 44,而其他机型则设置为 20。

    然后在你的viewDidLoad上,调用最近创建的方法:

    self.navigationController?.navigationBar.setGradientBackground(colors: [.red, .yellow])
    

    The result is something like this. In my case, the gradient uses alpha zero at the bottom of the navigationBar

    【讨论】:

    • 嗯,这是实现它的好方法,但现在我只检查了 static let IS_IPHONE_X = UIDevice.current.userInterfaceIdiom == .phone && max(UIScreen.main.bounds.size.width, UIScreen .main.bounds.size.height) == 812.0 if DeviceType.IS_IPHONE_X { defaultNavigationBarFrame = CGRect(x: 0, y: 0, width: sizeLength, height: 88) } else { defaultNavigationBarFrame = CGRect(x: 0, y: 0,宽度:sizeLength,高度:64)}
    【解决方案3】:

    使用UIImage.resizableImage() 拉伸图像怎么样: (这几乎是完美的解决方案)

    open class NavigationController: UINavigationController {
    
        var gradientColors = [UIColor]() {
            didSet {
                updateGradient()
            }
        }
    
        open func updateGradient() {
            guard gradientColors.count > 1 else {
                // There has to be at least two colors to set gradient..
                return
            }
            let gradient = CAGradientLayer()
            let defaultNavigationBarFrame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 64)
    
            gradient.frame = defaultNavigationBarFrame
            gradient.colors = gradientColors.map({ $0.cgColor })
    
            if let gradientImage = gradient.snapshotImage() {
                let image =  gradientImage.resizableImage(withCapInsets: UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1), resizingMode: UIImage.ResizingMode.stretch)
                UINavigationBar.appearance().setBackgroundImage(image, for: .default)
            }
        }
    }
    

    CALayer.snapshotImage() 实现:

    public extension CALayer {
        public func snapshotImage() -> UIImage? {
            return UIGraphicsImageRenderer(bounds: frame).image { (imageContext) in
                render(in: imageContext.cgContext)
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      您不仅不能再假设导航栏高度为 64,您也不能再假设静态高度。

      我认为实现您想要做的最简单的方法是使用UINavigationControllerinit(navigationBarClass:toolbarClass:) 方法和自定义UINavigationBar 子类,该子类覆盖layerClass 以直接指定您的CAGradientLayer

      不幸的是,我认为UIAppearance 没有办法“一劳永逸”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 1970-01-01
        相关资源
        最近更新 更多