【问题标题】:Why my background gradient view is not loading in my customer UINavigationController class为什么我的背景渐变视图没有加载到我的客户 UINavigationController 类中
【发布时间】:2017-09-01 23:40:57
【问题描述】:

我正在尝试为我的子类 NavigationController 的背景设置一个渐变。当我向相同的代码添加颜色时,它运行良好,但我似乎无法让我的渐变显示出来。我创建了一个 UIView 的子类,它返回一个 CAGradientLayer 作为其背景视图。

这是我的子类 UIView :(注意颜色很奇怪,所以我确信它加载了正确的渐变。

@IBDesignable
class GenericBackgrounView: UIView {

override class var layerClass: AnyClass {
    return CAGradientLayer.self
}


///The roundness for the corner
@IBInspectable var cornerRadius: CGFloat = 0.0 {
    didSet{
        setupGradient()
    }
}

func setupGradient() {
    //let gradientColors = [bgDarkColor.cgColor, bgDarkColor.blended(withFraction: 0.5, of: bgLightColor).cgColor, bgLightColor.cgColor]
    let gradientColors = [UIColor.brown.cgColor, UIColor.red.blended(withFraction: 0.5, of: UIColor.cyan).cgColor, UIColor.yellow.cgColor]
    gradientLayer.colors = gradientColors
    gradientLayer.locations = ESDefault.backgroundGradientColorLocations
    setNeedsDisplay()
}

var gradientLayer: CAGradientLayer {
    return self.layer as! CAGradientLayer
}

override func awakeFromNib() {
    super.awakeFromNib()
    setupGradient()
}
override func prepareForInterfaceBuilder() {
    setupGradient()
}

}

这是我的 UINavigationController : 类 GenericNavigationController: UINavigationController {

override func viewDidLoad() {
    super.viewDidLoad()
    let backView = GenericBackgrounView(frame: self.view.frame)
    backView.bounds = self.view.bounds
    self.view.backgroundColor = UIColor.clear
    self.view.addSubview(backView)
    self.view.sendSubview(toBack: backView)

    // Do any additional setup after loading the view.
}
}

还请注意,当我将 GenericBackgroundView 用于我在界面构建器中添加的任何视图时,它都可以正常工作。

我在这方面已经很久了。我想我会建议 Apple 在代码和 Interface Builder 中设置某种主题 API……以及将渐变直接添加到 Interface Builder 中的能力……

感谢您的帮助。

【问题讨论】:

  • 不要最小化 blended(withFraction: 0.5, of: UIColor) 函数,它是 UIColor 的扩展,我用系数创建了混合颜色。
  • viewDidLoad 为时过早,无法捕获 viewController 的 view 的运行时 frame。您是否尝试在视图显示在屏幕上后在调试器中打印渐变视图的框架?这可能会告诉你为什么它不在屏幕上。
  • 我想我可能对调试器不够了解,因为我不太明白你想告诉我什么。
  • 好的,例如,在上面粘贴的viewDidLoad 中的self.view.addSubview... 处放置一个断点。当断点命中时,它会冻结应用程序,在 Xcode 底部的调试器中,您可以键入p backView.frame,它会在控制台中打印帧。我怀疑你会看到高度/宽度为 0,或者类似的东西来解释为什么你没有在屏幕上看到它。
  • 啊,好吧...我通常在值窗口中使用 Epressions,并且我已经验证我得到了正确的帧。尽管如此,这里是打印的结果: print backView.frame (CGRect) $R2 = (origin = (x = 0, y = 0), size = (width = 375, height = 667))

标签: swift uiview background uinavigationcontroller gradient


【解决方案1】:

不要在 awakeFromNib() 中设置它,而是尝试在 viewDidLayoutSubviews() 中调用它。原因是在viewDidLayoutSubviews() 中会有正确的视图框架,而在awakeFromNib() 中你不会知道正确的视图框架。来自Apple Documentation

【讨论】:

  • 我再次尝试以防万一,但我遇到了同样的问题。在调用函数 GenericBackgrounView(frame: self.view.frame) 之前,我已经验证了视图的边界和框架已初始化。我已经为 UIView 的其他类型的子类添加了类似的问题,比如 UITableViewCell,而且看起来,即使它们都是 UIView 的子类,它们似乎也不喜欢渐变。我不能对所有这些都应用相同的代码。噗……
【解决方案2】:

好的,我稍微修改了一下,找到了一些工作代码。我仍然很想了解它起作用的原因,而不是我以前的方式。我讨厌感觉它是靠魔法起作用的……

这里是工作代码:(请记住,我的渐变是 CAGradientLayer 的形式,并且我已经创建了一些具有默认值的静态变量。

import UIKit

class GenericNavigationController: UINavigationController {
    let backViewGradient = Default.testGradientCALayer
    override func viewDidLoad() {
        super.viewDidLoad()
        setupBackground()
    }

    func setupBackground() {
        backViewGradient.frame = self.view.frame
        self.view.layer.insertSublayer(backViewGradient, at: 0)
    }

    override func prepareForInterfaceBuilder() {
        setupBackground()
    }
}

我想知道的是,从 UIView 子类化的所有 UIControl 的工作方式都不相同。它们都应该有一个作为背景的视图,我们都应该能够向它们添加层或子视图,并且能够让我以前的代码工作或我的最新代码也不能与 TableViewCells 一起工作。

我将保留这个问题,因为我很想知道这背后的真相。如果 Swift 或 Xcode 的行为有点神奇和不一致,我认为我无法完全掌握它。

【讨论】:

  • 我刚刚意识到,我只是失去了在 Interface Builder 中查看视图自定义设置的能力...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-10
  • 1970-01-01
  • 1970-01-01
  • 2020-08-26
  • 1970-01-01
  • 2011-09-26
  • 2017-06-22
相关资源
最近更新 更多