2009-08-12 3 views
23

эй, я хочу, чтобы иметь возможность градиентной заливки на текст в UILabel я знаю о CGGradient, но я не знаю, как я хотел бы использовать его на текст А, UILabel вКак добавить градиент к тексту UILabel, но не к фону?

я нашел это на Google, но я не могу управлять чтобы заставить его работать

http://silverity.livejournal.com/26436.html

+0

Это похоже на дубликат этого вопроса: http://stackoverflow.com/questions/422066/gradients -on-uiview-and-uilabels-on-iphone –

+5

На самом деле этот вопрос спрашивает, как добавить градиент на фоне uilabel без градиента к самому тексту – DotSlashSlash

+0

Извините, я неправильно задал ваш вопрос. Ниже приведен способ настройки градиента текста, а не фона. –

ответ

38

(Перейти вниз для исходного кода полного класса)

Действительно полезных ответов, как Брэд Ларсона и Бах , Второй работал для меня, но для этого требуется, чтобы изображение присутствовало заранее. Я хотел что-то более динамичное, так я объединил оба решения в одном:

  • нарисовать нужный градиент на UIImage
  • использовать UIImage, чтобы установить цвет рисунка на

Результат работы и на скриншоте ниже вы можете увидеть, как некоторые греческие символы тоже выглядят отлично.(Кроме того, я добавил обводку и тень на верхней части градиента)

iOS stylized UILabel, the big brown fox

Вот пользовательский метод инициализации моего лейбла наряду с методом, который оказывает градиент на UIImage (часть кода что функциональность я получил от блоге я не могу найти теперь ссылаться на него):

- (id)initWithFrame:(CGRect)frame text:(NSString *)aText { 
    self = [super initWithFrame:frame]; 
    if (self) { 
     self.backgroundColor = [UIColor clearColor]; 
     self.text = aText; 

     self.textColor = [UIColor colorWithPatternImage:[self gradientImage]]; 

    } 
    return self; 
} 

- (UIImage *)gradientImage 
{ 
    CGSize textSize = [self.text sizeWithFont:self.font]; 
    CGFloat width = textSize.width;   // max 1024 due to Core Graphics limitations 
    CGFloat height = textSize.height;  // max 1024 due to Core Graphics limitations 

    // create a new bitmap image context 
    UIGraphicsBeginImageContext(CGSizeMake(width, height)); 

    // get context 
    CGContextRef context = UIGraphicsGetCurrentContext();  

    // push context to make it current (need to do this manually because we are not drawing in a UIView) 
    UIGraphicsPushContext(context);        

    //draw gradient  
    CGGradientRef glossGradient; 
    CGColorSpaceRef rgbColorspace; 
    size_t num_locations = 2; 
    CGFloat locations[2] = { 0.0, 1.0 }; 
    CGFloat components[8] = { 0.0, 1.0, 1.0, 1.0, // Start color 
          1.0, 1.0, 0.0, 1.0 }; // End color 
    rgbColorspace = CGColorSpaceCreateDeviceRGB(); 
    glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations); 
    CGPoint topCenter = CGPointMake(0, 0); 
    CGPoint bottomCenter = CGPointMake(0, textSize.height); 
    CGContextDrawLinearGradient(context, glossGradient, topCenter, bottomCenter, 0); 

    CGGradientRelease(glossGradient); 
    CGColorSpaceRelease(rgbColorspace); 

    // pop context 
    UIGraphicsPopContext();        

    // get a UIImage from the image context 
    UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext(); 

    // clean up drawing environment 
    UIGraphicsEndImageContext(); 

    return gradientImage; 
} 

постараюсь завершить эту UILabel подкласс и отправить его.

EDIT:

Класс сделано, и это на my GitHub repository. Читайте об этом here!

+0

Это единственный ответ, который работает с многострочным текстом, спасибо! – jjxtra

+0

Любой шанс обновить это до Swift 4? –

0

Вы могли суб-класса из UILable и сделать метод рисования самостоятельно. Вероятно, это будет более сложный подход, возможно, будет более простой способ.

+0

yeh Я сделал это, но он градиент заполняет текст, который он просматривает на весь вид – DotSlashSlash

+0

Я имею в виду его * doesnt * заполнить текст – DotSlashSlash

14

В примере, который вы предоставляете, используются частные функции рисования текста, на которые у вас нет доступа на iPhone. Автор дает пример того, как это сделать, используя открытый API в subsequent post. В его более позднем примере используется градиентное изображение для цвета текста. (К сожалению, похоже, его блог с тех пор был удален, но см. за подход, который он использовал.)

Если вы все еще хотите нарисовать градиент для цвета текста в коде, это может быть сделано путем подкласса UILabel и переопределения -drawRect: иметь код вроде следующего в нем:

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextSaveGState(context); 
CGContextTranslateCTM(context, 0.0f, self.bounds.size.height); 
CGContextScaleCTM(context, 1.0f, -1.0f); 

CGContextSelectFont(context, "Helvetica", 20.0f, kCGEncodingMacRoman); 
CGContextSetTextDrawingMode(context, kCGTextClip); 
CGContextSetTextPosition(context, 0.0f, round(20.0f/4.0f)); 
CGContextShowText(context, [self.text UTF8String], strlen([self.text UTF8String])); 

CGContextClip(context); 

CGGradientRef gradient; 
CGColorSpaceRef rgbColorspace; 
size_t num_locations = 2; 
CGFloat locations[2] = { 0.0, 1.0 }; 
CGFloat components[8] = { 1.0, 1.0, 1.0, 1.0, // Start color 
    1.0, 1.0, 1.0, 0.1 }; // End color 

rgbColorspace = CGColorSpaceCreateDeviceRGB(); 
gradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations); 

CGRect currentBounds = self.bounds; 
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f); 
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds)); 
CGContextDrawLinearGradient(context, gradient, topCenter, midCenter, 0); 

CGGradientRelease(gradient); 
CGColorSpaceRelease(rgbColorspace);   

CGContextRestoreGState(context); 

Одним из недостатков этого подхода состоит в том, что функции Core Graphics, которые я использую не обрабатывать текст Unicode правильно.

Что делает код, он переворачивает контекст чертежа вертикально (iPhone инвертирует нормальную систему координат кварца для оси Y), устанавливает режим текстового рисования, чтобы пересечь нарисованный текст с обтравочным контуром, закрепил область рисуем текст, а затем рисуем градиент. Градиент будет заполнять только текст, а не фон.

Я пробовал использовать метод NDString -drawAtPoint: для этого, который поддерживает Unicode, но все символы запускались друг над другом, когда я переключил текстовый режим на kCGTextClip.

+11

спасибо за это :) Я просто использовал метод изображения рисунка \t label.textColor = [UIColor colorWithPatternImage: gradientImage; – DotSlashSlash

+0

Ссылка сломана .... – jjxtra

+0

@PsychoDad - К сожалению, похоже, что весь его блог удален, но ключевая информация из него зафиксирована в ответе Баха, и остальная часть ответа здесь все еще стоит. Димитрис даже расширил это в своем ответе. Спасибо, что указали это. –

104

Я искал решение, и у DotSlashSlash есть ответ, спрятанный в одном из комментариев!

Для полноты картины, ответ и самое простое решение:

UIImage *myGradient = [UIImage imageNamed:@"textGradient.png"]; 
myLabel.textColor = [UIColor colorWithPatternImage:myGradient]; 
+3

Просто блестящий. –

+0

Awesome - спасибо нагрузкам. – SomaMan

+0

Это работает очень хорошо! Гораздо чище, чем основное графическое решение! –

8

СВИФТ 3+

Это решение основано на @ ответ Димитрис в. Это расширение класса UILabel, которое создаст градиент над текстом ярлыка за пройденный startColor и endColor. Расширение UILabel ниже:

extension UILabel { 

    func applyGradientWith(startColor: UIColor, endColor: UIColor) -> Bool { 

     var startColorRed:CGFloat = 0 
     var startColorGreen:CGFloat = 0 
     var startColorBlue:CGFloat = 0 
     var startAlpha:CGFloat = 0 

     if !startColor.getRed(&startColorRed, green: &startColorGreen, blue: &startColorBlue, alpha: &startAlpha) { 
      return false 
     } 

     var endColorRed:CGFloat = 0 
     var endColorGreen:CGFloat = 0 
     var endColorBlue:CGFloat = 0 
     var endAlpha:CGFloat = 0 

     if !endColor.getRed(&endColorRed, green: &endColorGreen, blue: &endColorBlue, alpha: &endAlpha) { 
      return false 
     } 

     let gradientText = self.text ?? "" 

     let name:String = NSFontAttributeName 
     let textSize: CGSize = gradientText.size(attributes: [name:self.font]) 
     let width:CGFloat = textSize.width 
     let height:CGFloat = textSize.height 

     UIGraphicsBeginImageContext(CGSize(width: width, height: height)) 

     guard let context = UIGraphicsGetCurrentContext() else { 
      UIGraphicsEndImageContext() 
      return false 
     } 

     UIGraphicsPushContext(context) 

     let glossGradient:CGGradient? 
     let rgbColorspace:CGColorSpace? 
     let num_locations:size_t = 2 
     let locations:[CGFloat] = [ 0.0, 1.0 ] 
     let components:[CGFloat] = [startColorRed, startColorGreen, startColorBlue, startAlpha, endColorRed, endColorGreen, endColorBlue, endAlpha] 
     rgbColorspace = CGColorSpaceCreateDeviceRGB() 
     glossGradient = CGGradient(colorSpace: rgbColorspace!, colorComponents: components, locations: locations, count: num_locations) 
     let topCenter = CGPoint.zero 
     let bottomCenter = CGPoint(x: 0, y: textSize.height) 
     context.drawLinearGradient(glossGradient!, start: topCenter, end: bottomCenter, options: CGGradientDrawingOptions.drawsBeforeStartLocation) 

     UIGraphicsPopContext() 

     guard let gradientImage = UIGraphicsGetImageFromCurrentImageContext() else { 
      UIGraphicsEndImageContext() 
      return false 
     } 

     UIGraphicsEndImageContext() 

     self.textColor = UIColor(patternImage: gradientImage) 

     return true 
    } 

} 

И использование:

let text = "YAAASSSSS!" 
label.text = text 
if label.applyGradientWith(startColor: .red, endColor: .blue) { 
    print("Gradient applied!") 
} 
else { 
    print("Could not apply gradient") 
    label.textColor = .black 
} 

YAAASSSSS!


СВИФТ 2

class func getGradientForText(text: NSString) -> UIImage { 

    let font:UIFont = UIFont(name: "YourFontName", size: 50.0)! 
    let name:String = NSFontAttributeName 
    let textSize: CGSize = text.sizeWithAttributes([name:font]) 
    let width:CGFloat = textSize.width   // max 1024 due to Core Graphics limitations 
    let height:CGFloat = textSize.height  // max 1024 due to Core Graphics limitations 

    //create a new bitmap image context 
    UIGraphicsBeginImageContext(CGSizeMake(width, height)) 

    // get context 
    let context = UIGraphicsGetCurrentContext() 

    // push context to make it current (need to do this manually because we are not drawing in a UIView) 
    UIGraphicsPushContext(context!) 

    //draw gradient 
    let glossGradient:CGGradientRef? 
    let rgbColorspace:CGColorSpaceRef? 
    let num_locations:size_t = 2 
    let locations:[CGFloat] = [ 0.0, 1.0 ] 
    let components:[CGFloat] = [(202/255.0), (197/255.0), (52/255.0), 1.0, // Start color 
           (253/255.0), (248/255.0), (101/255.0), 1.0] // End color 
    rgbColorspace = CGColorSpaceCreateDeviceRGB(); 
    glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations); 
    let topCenter = CGPointMake(0, 0); 
    let bottomCenter = CGPointMake(0, textSize.height); 
    CGContextDrawLinearGradient(context, glossGradient, topCenter, bottomCenter, CGGradientDrawingOptions.DrawsBeforeStartLocation); 

    // pop context 
    UIGraphicsPopContext(); 

    // get a UIImage from the image context 
    let gradientImage = UIGraphicsGetImageFromCurrentImageContext(); 

    // clean up drawing environment 
    UIGraphicsEndImageContext(); 

    return gradientImage; 
} 

Принадлежит к @Dimitris

+0

Не работает, когда я помещаю его в ImageView, весь вид желтый и в нем нет текста ... –

+0

Не работает в Swift 4, много ошибок –

+0

Вы правы @ J.Doe. Я обновил свой ответ с помощью решения для Swift 3+. Также я включил свой собственный поворот с расширением 'UILabel', который поместит градиент в' UIColor' и применит его к самой метке. Пожалуйста, дайте мне знать, есть ли другие проблемы. –

3

Вот что я делаю в Swift 3

override func viewDidLoad() { 
    super.viewDidLoad() 
    timerLabel.textColor = UIColor(patternImage: gradientImage(size: timerLabel.frame.size, color1: CIColor(color: UIColor.green), color2: CIColor(color: UIColor.red), direction: .Left)) 
} 

func gradientImage(size: CGSize, color1: CIColor, color2: CIColor, direction: GradientDirection = .Up) -> UIImage { 

    let context = CIContext(options: nil) 
    let filter = CIFilter(name: "CILinearGradient") 
    var startVector: CIVector 
    var endVector: CIVector 

    filter!.setDefaults() 

    switch direction { 
    case .Up: 
     startVector = CIVector(x: size.width * 0.5, y: 0) 
     endVector = CIVector(x: size.width * 0.5, y: size.height) 
    case .Left: 
     startVector = CIVector(x: size.width, y: size.height * 0.5) 
     endVector = CIVector(x: 0, y: size.height * 0.5) 
    case .UpLeft: 
     startVector = CIVector(x: size.width, y: 0) 
     endVector = CIVector(x: 0, y: size.height) 
    case .UpRight: 
     startVector = CIVector(x: 0, y: 0) 
     endVector = CIVector(x: size.width, y: size.height) 
    } 

    filter!.setValue(startVector, forKey: "inputPoint0") 
    filter!.setValue(endVector, forKey: "inputPoint1") 
    filter!.setValue(color1, forKey: "inputColor0") 
    filter!.setValue(color2, forKey: "inputColor1") 

    let image = UIImage(cgImage: context.createCGImage(filter!.outputImage!, from: CGRect(x: 0, y: 0, width: size.width, height: size.height))!) 
    return image 
} 
0

Простейшее Swift 3 Решение

Добавить изображение в ваших активов проекта или создать программно затем сделать следующие:

let image = UIImage(named: "myGradient.png")! 
label.textColor = UIColor.init(patternImage: image)