UINavigationBar背景图片实现scaleAspectFill效果

4

tl;dr

我想为UINavigationBar设置背景图片。有没有一种方法可以配置这个navbar,使其使用scaleAspectFill-like的行为(就像一个将contentMode设置为scaleAspectFillUIImageView)?


目标

我有一张大约适合横向iPhone导航栏的图像(高度为64pt,宽度约为800pt;确切的尺寸在这里不重要),我用 navigationBar.setBackgroundImage(img, for: .default)设置了它作为背景图片。该图像是一张模糊的照片,所以不需要像素完美。顺便说一下 - 我正在使用 UINavigationBar.appearance 来为所有导航栏同时设置背景。

  1. 我希望它能够在纵向方向时显示图像的中心部分,在横向方向时则不裁剪地显示整个图像。如果高度不完全匹配(如在iPhone X上所期望的那样),它应该稍微缩放一下以填充额外的高度。

  2. 作为后备解决方案,我也会接受中心显示较小宽度的图像,并通过拉伸第一列和最后一列像素来填充额外的水平空间。

我到目前为止尝试过的

  • 目标1:设置UINavigationBarcontentMode -- 在渲染图像时似乎被忽略了
  • 目标2:使用较小的图像,并使用stretchableImage(withLeftCapWidth:topCapHeight:)使其可伸缩 -- 填充了导航栏,但是图像被推到右下角(显然是因为此方法只考虑左边和顶部作为可伸缩的边界)
  • 目标2:使用较小的图像并使用 resizableImage(withCapInsets:resizingMode:),将resizingMode设置为stretch -- 在横向方向上,它只是将图像拉伸到完整的宽度,而忽略了容器插图(可能这个方法不做我想象的那样)。
2个回答

6
通过为UINavigationController的视图添加一个图像视图来解决问题,如此处所述。图像视图附加在导航控制器视图的顶部、左侧和右侧以及导航栏的底部。
与文章中的示例相反,我不使用自定义导航栏;而是将图像视图插入现有导航栏背后。请注意,导航栏必须透明才能使其正常工作。此外,图像视图必须被裁剪,否则它会奇怪地延伸到导航栏的底部之外。
也许这对其他人有所帮助,因此这里提供一些代码(这应该仅应用于一个导航控制器,因此您最好将此代码放在子类中而不是扩展中):
extension UINavigationController {
  func setBackgroundImage(_ image: UIImage) {
    navigationBar.isTranslucent = true
    navigationBar.barStyle = .blackTranslucent

    let logoImageView = UIImageView(image: image)
    logoImageView.contentMode = .scaleAspectFill
    logoImageView.clipsToBounds = true
    logoImageView.translatesAutoresizingMaskIntoConstraints = false

    view.insertSubview(logoImageView, belowSubview: navigationBar)
    NSLayoutConstraint.activate([
      logoImageView.leftAnchor.constraint(equalTo: view.leftAnchor),
      logoImageView.rightAnchor.constraint(equalTo: view.rightAnchor),
      logoImageView.topAnchor.constraint(equalTo: view.topAnchor),
      logoImageView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor)
    ])
  }
}

1
我尝试了这种方法,但在iOS 11中,我只有半透明的导航栏。ImageView存在于视图层次结构中,但它不可见。 - humblePilgrim

1

您可以尝试将UIImageViewcontentMode = .scaleAspectFill直接添加到UINavigationBar中,如下所示:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let imgView = UIImageView(image: UIImage(named: "desert"))
        imgView.contentMode = .scaleAspectFill
        imgView.frame = self.navigationController!.navigationBar.frame
        self.navigationController?.navigationBar.addSubview(imgView)
        self.navigationController?.navigationBar.sendSubview(toBack: imgView)
    }
}

结果是:

enter image description here


谢谢你的回答。不幸的是,我有一些布局问题。问题1:图像没有覆盖整个状态栏区域,它留下了顶部几个像素。问题2:图像重叠在导航控制器内视图控制器的顶部,遮挡了其内容。我知道我可以手动调整框架,但那似乎相当hacky... 有什么好的自动布局锚点魔法来解决这个问题吗? - dr_barto
我添加了自己的解决方案,受到了你的答案的启发 - 谢谢! - dr_barto

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