10

我想以编程方式更改tintColorUINavigationBar 的,并保持界面生成器中的渐变。

当我tintColor在我的代码中更改时,渐变会消失,但是当我tintColor在 Interface Builder 中更改时,渐变会被保留。

有任何想法吗?

4

5 回答 5

20

所以这是一个老问题,但是当我在寻找听起来像这个问题但不同的东西时,我偶然发现了它。希望它可以帮助其他人(或者其他人会告诉我更好的方法)......

如何在 UINavigationBar 上实现自定义渐变?

首先,让我们以通常的方式获取我们的自定义渐变(作为 CALayer):

- (CALayer *)gradientBGLayerForBounds:(CGRect)bounds
{
    CAGradientLayer * gradientBG = [CAGradientLayer layer];
    gradientBG.frame = bounds;
    gradientBG.colors = @[ (id)[[UIColor redColor] CGColor], (id)[[UIColor purpleColor] CGColor] ];
    return gradientBG;
}

我们开始了,一个看起来像是朋克摇滚乐的可疑化妆选择的渐变,这很好,因为此代码用于假设的应用程序I Have A Punk-Rocker With Questionable Tastes In My Pocket。我这个名字有点太长了..

现在我想要我的 UINavigationBar 上的这个层,这应该很容易吧?只需将其添加为子图层,对吗?这里的问题是它会掩盖 UINavigationController 给你的美妙的按钮和东西。那很糟。

相反,让我们看一下我们在 iOS5+ 中用于更改应用程序中所有 UINavigationBar(s) 外观的绝妙便捷方法:

[[UINavigationBar appearance] setBackgroundImage:SOME_IMAGE
                                   forBarMetrics:UIBarMetricsDefault];

这里唯一的问题是我们没有 UIImage,我们有一个 CALayer。朋克摇滚爱好者应该做什么?

CALayer * bgGradientLayer = [self gradientBGLayerForBounds:ONE_OF_YOUR_NAV_CONTROLLERS.navigationBar.bounds];
UIGraphicsBeginImageContext(bgGradientLayer.bounds.size);
[bgGradientLayer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * bgAsImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

所以现在我们已经将我们的 CALayer 转换为 UIImage(希望如此),所以剩下的就是设置它:

if (bgAsImage != nil)
{
    [[UINavigationBar appearance] setBackgroundImage:bgAsImage
                                       forBarMetrics:UIBarMetricsDefault];
}
else
{
    NSLog(@"Failded to create gradient bg image, user will see standard tint color gradient.");
}

我喜欢这个解决方案的地方是

  • 我的应用程序中所有 UINavigationBar(s) 的集中式代码(在 AppDelegate 中)
  • 所有 UINavigation 按钮(后退、编辑等)仍将使用 tintColor
  • 如果 UIImage 创建失败,我的 UINavigationBar(s) 仍将遵循 tintColor
  • 我不必依赖实际的图像资源/易于更新

但我仍然不相信这是最好的方法。所以,如果它对你有帮助,请尽情享受,如果可以的话,让我知道如何改进它。

~ 谢谢

于 2013-02-26T21:45:44.640 回答
14

将 barStyle 设置为 UIBarStyleBlackTranslucent 像这样设置 tintColor:

navigationBar.tintColor = [UIColor colorWithRed:.7 green:.5 blue:.2 alpha:1];

这将设置适当的渐变。使用您需要的任何组合。

于 2009-02-08T00:32:36.030 回答
1

我只是把它写成 Swift 2.0 的 UIImage 扩展。也许它有点用处。

extension UIImage {

    class func convertGradientToImage(colors: [UIColor], frame: CGRect) -> UIImage {

        // start with a CAGradientLayer
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = frame

        // add colors as CGCologRef to a new array and calculate the distances
        var colorsRef : [CGColorRef] = []
        var locations : [NSNumber] = []

        for i in 0 ... colors.count-1 {
            colorsRef.append(colors[i].CGColor as CGColorRef)
            locations.append(Float(i)/Float(colors.count))
        }

        gradientLayer.colors = colorsRef
        gradientLayer.locations = locations

        // now build a UIImage from the gradient
        UIGraphicsBeginImageContext(gradientLayer.bounds.size)
        gradientLayer.renderInContext(UIGraphicsGetCurrentContext()!)
        let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        // return the gradient image
        return gradientImage
    }
}

像这样称呼它:

let colors = [
    UIColor.blueColor(),
    UIColor.greenColor()
    // and many more if you wish
]
let gradientImage = UIImage.convertGradientToImage(colors, frame: navigationBar.bounds)
navigationBar.setBackgroundImage(gradientImage, forBarMetrics: .Default)
于 2015-09-21T13:08:15.240 回答
0
navigation.tintColor = [UIColor colorWithRed:0.47f green:0.23f blue:0.61f alpha:1.0f];
于 2012-04-03T12:46:22.700 回答
0

使用 maskView 的好方法

// create gradient view
let gradientView: UIView = UIView(frame: frame)
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = gradientView.bounds
gradient.colors = [UIColor.grayColor().CGColor, UIColor.clearColor().CGColor]
gradientView.layer.insertSublayer(gradient, atIndex: 0)

//set appearance 
UINavigationBar.appearance().maskView = gradientView
于 2016-03-21T07:14:45.790 回答