带渐变的UINavigationBar tintColor

时间:2009-01-30 09:45:19

标签: iphone cocoa-touch interface-builder

我想在程序上更改UINavigationBar的tintColor并保持渐变,就像在Interface Builder中一样。

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

有什么想法吗?

5 个答案:

答案 0 :(得分: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;
}

我们走了,这个渐变看起来像是一个朋克摇滚歌手的可疑化妆选择,这很好,因为这段代码适用于假想的应用我有一个朋克摇滚乐,口袋里有可疑的口味。这个名字我有点太长了..

现在我想在我的UINavigationBar上使用这个图层,这应该很容易吗?只需将其添加为子图层,对吧?这里的问题是它将掩盖UINavigationController为您提供的精彩按钮和内容。那很糟糕。

相反,让我们看看我们在iOS5 +中使用的非常方便的方法来改变我们应用中所有UINavigationBar的外观:

[[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的集中代码(在AppDelegate中)
  • tintColor仍然适用于所有UINavigation按钮(返回,编辑等)
  • 如果UIImage创建失败,我的UINavigationBar仍然会尊重tintColor
  • 我不必依赖实际的图像资源/易于更新

但我仍然不相信这是最好的方式。所以,如果它可以帮助你,请尽情享受,如果可以,请告诉我如何改进它。

〜谢谢

答案 1 :(得分:14)

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

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

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

答案 2 :(得分: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)

答案 3 :(得分:0)

navigation.tintColor = [UIColor colorWithRed:0.47f green:0.23f blue:0.61f alpha:1.0f];

答案 4 :(得分: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