处理iPhone X中导航栏背景渐变问题

5
迄今为止,我按以下方式处理导航栏中的渐变_
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”作为渐变的导航栏高度,我遇到了问题,如下图所示_

enter image description here

请建议一种可以在每种情况下动态使用的解决方法。

4个回答

4

借助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尺寸(44),如果程序检测到正在使用iPhone X(因为屏幕高度为2436)。

你可以使用updatedFrame.size.height += navigationBar.frame.maxY,这样你就不必检查设备了。 - Paolo Musolino

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变量设置为44,其他型号则为20。

然后在viewDidLoad中,只需调用最近创建的方法:

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

结果大致如此。在我的情况下,渐变在navigationBar底部使用了alpha零


这是一种不错的实现方式,但目前我只是检查了static let IS_IPHONE_X = UIDevice.current.userInterfaceIdiom == .phone && max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height) == 812.0如果 DeviceType.IS_IPHONE_X { defaultNavigationBarFrame = CGRect(x: 0, y: 0, width: sizeLength, height: 88) } else { defaultNavigationBarFrame = CGRect(x: 0, y: 0, width: sizeLength, height: 64) } - Piyush Mathur

2
像这样使用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)
        }
    }
}

0

现在你不能再假设导航栏高度为64,也不能再假设高度是静态的。

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

不幸的是,我认为没有一种方法可以使用UIAppearance来“点火并忘记”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接