UINavigationBar tintColor с градиентом

Я хочу изменить программный код tintColor UINavigationBar и сохранить градиент, как в Interface Builder.

Когда я изменяю tintColor в моем коде, градиент исчезает, но когда я изменяю tintColor в Interface Builder, сохраняется градиент.

Любые идеи?

Ответ 1

Итак, это старый вопрос, но я наткнулся на него, когда искал что-то похожее на этот вопрос, но он другой. В надежде, что это поможет кому-то другому (или что кто-то еще покажет мне лучший способ)...

Как реализовать пользовательский градиент на 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, который должен быть легким ya? Просто добавьте его как подуровень, не так ли? Проблема здесь в том, что он скроет прекрасные кнопки и прочее, что дает вам 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.");
}

Что мне нравится в этом решении,

  • централизованный код (в AppDelegate) для всех UINavigationBar (s) в моем приложении
  • tintColor будет по-прежнему выполняться для всех кнопок UINavigation (назад, редактировать и т.д.).
  • Если создание UIImage завершится неудачно, мои UINavigationBar (s) по-прежнему будут соблюдать tintColor
  • Мне не нужно зависеть от реального ресурса изображения/легко обновлять

Но я все еще не убежден, что это лучший способ. Поэтому, наслаждайтесь, если это поможет вам, дайте мне знать, как улучшить его, если сможете.

~ Спасибо

Ответ 2

Установите barStyle в UIBarStyleBlackTranslucent Установите tintColor следующим образом:

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

Это установит соответствующий градиент. Используйте любую комбинацию, в которой вы нуждаетесь.

Ответ 3

Я просто написал это как расширение UIImage для Swift 2.0. Может быть, это пригодится.

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)

Ответ 4

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

Ответ 5

Хороший способ использования 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