2009-08-12 13 views
23

hej, chcę mieć możliwość wypełnienia gradientem na tekst w UILabel wiem o CGGradient ale nie wiem, jak chciałbym używać go na tekstu w UILabel zaJak dodać gradient do tekstu UILabel, ale nie do tła?

Znalazłem to na google, ale nie mogę zarządzać aby zmusić go do pracy

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

+0

Wygląda na to, że jest to duplikat tego pytania: http://stackoverflow.com/questions/422066/gradients -on-uiview-and-uilabels-on-iphone –

+5

właściwie to pytanie pyta, jak dodać gradient na tle uilabel, bez gradientu do samego tekstu. – DotSlashSlash

+0

Niestety, źle odczytałem twoje pytanie. Poniżej znajdziesz sposób ustawienia gradientu na tekst, a nie tło. –

Odpowiedz

38

(Przejdź do dołu do kodu źródłowego pełne klasy)

naprawdę użyteczne odpowiedzi zarówno przez Brad Larson i Bacha . Drugi pracował dla mnie, ale wymaga obecności obrazu z wyprzedzeniem. Chciałem coś bardziej dynamicznego więc łączyć oba roztwory do jednego:

  • narysować żądany gradientu na UIImage
  • użyć UIImage ustawić barwny wzór

wynikiem prac i na zrzucie ekranu poniżej możesz zobaczyć kilka greckich znaków również.(I także przyczyniają się do skoku i cień na wierzchu gradientu)

iOS stylized UILabel, the big brown fox

tutaj zwyczaj sposób inicjujących moim etykiety wraz ze sposobem, który sprawia, gradient w UIImage (część kodzie że funkcjonalność mam z blogu nie mogę znaleźć teraz odwołać go):

- (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; 
} 

postaram się wypełnić tę UILabel podklasy i umieścić go.

EDIT:

Klasa jest zrobione i to na my GitHub repository. Przeczytaj o tym here!

+0

To jest jedyna odpowiedź, która działa z tekstem wielowierszowym, dziękuję! – jjxtra

+0

Czy masz szansę zaktualizować to do Swift 4? –

0

mogłeś podklasa się UILable i zrobić metodę draw siebie. Prawdopodobnie byłoby to trudniejsze podejście, może być łatwiejszy sposób.

+0

tak zrobiłem, ale to gradient wypełnia się nad tekstem, który przechodzi nad całym widokiem – DotSlashSlash

+0

mam na myśli * nie * wypełnienie tekstu – DotSlashSlash

14

Podany przykład zależy od prywatnych funkcji rysowania tekstu, do których nie masz dostępu w telefonie iPhone. Autor podaje przykład, jak to zrobić przy użyciu publicznego interfejsu API w subsequent post. Jego późniejszy przykład wykorzystuje obraz gradientowy dla koloru tekstu. (Niestety, wydaje się, jego blog został już usunięty, ale zobaczyć Bach's answer here dla podejścia użył.)

Jeśli nadal chcesz narysować gradient do koloru tekstu w kodzie, można to zrobić przez instacji UILabel i przesłanianie -drawRect: mieć kod jak poniżej w nim:

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); 

Jedną wadą tego podejścia jest to, że funkcje rdzenia graficznego używam nie obsługują Unicode poprawnie.

To, co robi kod, odwraca kontekst rysunku pionowo (iPhone odwraca normalny układ współrzędnych kwarcu włączony dla osi Y), ustawia tryb rysowania tekstu, aby przecinał narysowany tekst ze ścieżką przycinającą, przycina obszar do narysuj tekst, a następnie narysuj gradient. Gradient wypełni tylko tekst, a nie tło.

Próbowałem użyć metody NSString -drawAtPoint: do tego, która obsługuje Unicode, ale wszystkie znaki biegły jeden na drugim, gdy przełączyłem tryb tekstowy na kCGTextClip.

+11

dzięki za to :) i po prostu użyłem metody obrazu wzoru \t label.textColor = [UIColor colorWithPatternImage: gradientImage; – DotSlashSlash

+0

Link zepsuty .... – jjxtra

+0

@PsychoDad - Niestety wygląda na to, że cały jego blog został usunięty, ale kluczowe informacje z niego pochodzą z odpowiedzi Bacha, a reszta odpowiedzi tutaj nadal jest aktualna. Dimitris nawet rozwinął to w swojej odpowiedzi. Dziękuję za wskazanie. –

104

Szukałem rozwiązania, a DotSlashSlash ma odpowiedź ukrytą w jednym z komentarzy!

Dla kompletności, odpowiedź i najprostszym rozwiązaniem jest:

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

Po prostu genialny. –

+0

Awesome - thanks loads. – SomaMan

+0

Działa to bardzo dobrze! Znacznie czystsze niż podstawowe rozwiązanie graficzne! –

8

SWIFT 3+

Rozwiązanie to opiera się na odpowiedzi @ Dimitris za. Jest to rozszerzenie klasy UILabel, które tworzy gradient nad tekstem etykiety za przekazany startColor i endColor. Rozszerzenie UILabel jest poniżej:

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 
    } 

} 

i użytkowania:

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!


SWIFT 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; 
} 

Rekwizyty do @Dimitris

+0

Nie działa po umieszczeniu go w ImageView cały widok jest żółty i nie ma w nim żadnego tekstu ... –

+0

Nie działa w Swift 4, wiele błędów –

+0

Masz rację @ J.Doe. Zaktualizowałem swoją odpowiedź za pomocą rozwiązania dla Swift 3+. Dodałem także własny zwrot z rozszerzeniem 'UILabel', który umieści gradient w" UIColor "i zastosuje go do samej etykiety. Daj mi znać, jeśli pojawią się inne problemy. –

3

oto co robię w 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

Najprostszy Swift 3 Rozwiązanie

dodać zdjęcie do aktywów projektu lub utworzyć jeden programowo następnie wykonaj następujący:

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