2017-09-01 1 views
1

Ich versuche, eine Tabellenansicht (benutzerdefinierte Klasse nicht UITableView), in dem die Ergebnisse einen Farbverlauf unten wie im Beispiel Bild haben zu erstellen:Wie kann ich einen Farbverlaufseffekt mit Farbeinteilungen erzeugen?

enter image description here

Was ich versuchte:

  1. Es ist mir gelungen, den richtigen Gradienten als Hintergrund für jede Tabellenzelle hinzuzufügen, aber ich brauche es, um die Farbe des Textes jedes Etiketts zu sein, nicht den Hintergrund jeder Zelle. Question. (Ich habe diese ein.)

FAILED atempt:

enter image description here

  1. Erstellen eines benutzerdefinierten Gradientenbild und Hinzufügen als colorWithPatternImage: zu jedem Etikett aber seit Der Gradient ist einer, jede Zelle sieht gleich aus. Question.

atempt FAILED:

enter image description here

Letzte, was zu versuchen:

Sie zwei Farben Angenommen haben, color1 und color2. Ein Farbverlauf kann durch Mischen dieser Farben entstehen. Im Bild oben ist color1 = lila und color2 = orange. Es wäre einfach, einen Farbverlaufseffekt zu erstellen, indem Sie den Farbverlauf in Abschnitte basierend auf der Anzahl der Ergebnisse teilen und dann die durchschnittliche Farbe jedes Abschnitts finden und diese als Textfarbe für jedes entsprechende Ergebnis verwenden.

Zum Beispiel:

5 Ergebnisse = 5 Divisionen.

  • Divisionen1 = lila
  • division2 = weniger lila, mehr Orange
  • division3 = gleich lila, gleich Orange
  • division4 = mindestens lila, die meisten Orange
  • division5 = orange

Das Ergebnis ist nicht so detailliert, da jeder Text eine einfarbige Farbe hat, aber es ist ebenso beeindruckend, wenn der Text klein ist:

enter image description here

Das Problem ist, für zwei Farben wie diese:

Lila: 128,0, 0,0, 255,0

Orange: 255,0, 128,0, 0,0

Wie Sie es aufteilen in 5 Abschnitte und finden Sie den Durchschnitt der einzelnen Abschnitte?

Ich könnte dies mit dem Pipette-Tool in Pixelmator tun, aber nur wenn ich die feste Anzahl der Ergebnisse kannte, wird nicht mit 6 Ergebnissen arbeiten.

Ich kann es mit Mathe nicht nähern, ich weiß nicht, wo ich anfangen soll.

Irgendwelche Ideen?

Antwort

1

Sie können die RGB-Werte der Farben mathematisch verwenden.

Um die rgb-Werte zu erhalten, können Sie die Methode getRed:green:blue:alpha unter UIColor verwenden. Dann müssen Sie nur noch die Farben zusammenrechnen, basierend darauf, wie viele Abschnitte Sie benötigen.

Hier ist eine Funktion, die ein Array von Farben basierend auf einer Start- und Endfarbe und wie viele Divisionen Sie benötigen.

Lösung

func divideColors(firstColor: UIColor, secondColor: UIColor, sections: Int) -> [UIColor] { 

    // get rgb values from the colors 
    var firstRed: CGFloat = 0; var firstGreen: CGFloat = 0; var firstBlue: CGFloat = 0; var firstAlpha: CGFloat = 0; 
    firstColor.getRed(&firstRed, green: &firstGreen, blue: &firstBlue, alpha: &firstAlpha) 
    var secondRed: CGFloat = 0; var secondGreen: CGFloat = 0; var secondBlue: CGFloat = 0; var secondAlpha: CGFloat = 0; 
    secondColor.getRed(&secondRed, green: &secondGreen, blue: &secondBlue, alpha: &secondAlpha) 

    // function to mix the colors 
    func mix(_ first: CGFloat, _ second: CGFloat, ratio: CGFloat) -> CGFloat { return first + ratio * (second - first) } 

    // variable setup 
    var colors = [UIColor]() 
    let ratioPerSection = 1.0/CGFloat(sections) 

    // mix the colors for each section 
    for section in 0 ..< sections { 
     let newRed = mix(firstRed, secondRed, ratio: ratioPerSection * CGFloat(section)) 
     let newGreen = mix(firstGreen, secondGreen, ratio: ratioPerSection * CGFloat(section)) 
     let newBlue = mix(firstBlue, secondBlue, ratio: ratioPerSection * CGFloat(section)) 
     let newAlpha = mix(firstAlpha, secondAlpha, ratio: ratioPerSection * CGFloat(section)) 
     let newColor = UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: newAlpha) 
     colors.append(newColor) 
    } 

    return colors 

} 

Ihre Frage als Objective-C markiert ist, aber es sollte den Swift-Code über Objective-C leicht genug sein, um zu konvertieren, da Sie das gleiche UIColor API verwenden würden.

Hier ist ein Code zum Testen der obigen Funktion (perfekt für einen Swift Spielplatz).

Testing-Code

let sections = 5 
let view = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 50)) 
for (index, color) in divideColors(firstColor: UIColor.purple, secondColor: UIColor.orange, sections: sections).enumerated() { 
    let v = UIView(frame: CGRect(x: CGFloat(index) * 250/CGFloat(sections), y: 0, width: 250/CGFloat(sections), height: 50)) 
    v.backgroundColor = color 
    view.addSubview(v) 
} 
view.backgroundColor = .white 

Tester

An image of the five colors, evenly divided between purple and orange

Es funktioniert auch für eine beliebige Anzahl von Abschnitten und verschiedenen Farben!

An image of more colors, evenly divided between red and yellow

+0

Wenn Sie das nur in Objective-c veröffentlichen könnten. – Vulkan

+0

@Vulkan Die APIs und die Logik sind alle gleich, egal ob Sie Swift oder Objective-C verwenden. Es gibt existierende SO-Antworten, die beschreiben, wie all diese Dinge zu tun sind (rgb-Werte von einem 'UIColor' erhalten, ein Array erstellen und modifizieren usw.) – nathan

+0

Sie haben Recht, aber ich kann Swift nicht lesen und ich lese diese: "firstColor. getRed (& firstRed, grün: & firstGreen, blue: & firstBlue, alpha: & firstAlpha) "," func mix (_ zuerst: CGFloat, _ zweites: CGFloat, Verhältnis: CGFloat) -> CGFloat {return first + ratio * (zweites - erstes) } ". Ich kann sie nicht lesen und kann sie nicht in ObjC konvertieren. – Vulkan

0

Nun, hier ist, wie am Ende des einfarbigen mathy Bit zu tun:

Wenn Sie n + 1 Farben, für 0 < = m < = n:

color.red[m] = (purple.red * (m/n)) + (orange.red * ((n-m)/n); 
color.green[m] = (purple.green * (m/n)) + (orange.green * ((n-m)/n)); 
color.blue[m] = (purple.blue * (m/n)) + (orange.blue * ((n-m)/n)); 

Hoffnung das hilft.

1

So möchten Sie dies:

screenshot

Es gibt mehrere Möglichkeiten, dies implementieren könnte. Hier ist ein Weg, der pixelgenau ist (er zeichnet den Farbverlauf durch die Etiketten, anstatt jedes Etikett zu einer Volltonfarbe zu machen).

Machen Sie eine Unterklasse von UILabel. Überschreiben Sie in Ihrer Unterklasse drawTextInRect:, um den Farbverlauf zu zeichnen.

Lassen Sie uns die Unterklasse wie folgt erklären:

IB_DESIGNABLE 
@interface GradientLabel: UILabel 

@property (nonatomic, weak) IBOutlet UIView *gradientCoverageView; 
@property (nonatomic, strong) IBInspectable UIColor *startColor; 
@property (nonatomic, strong) IBInspectable UIColor *endColor; 

@end 

Schließen Sie den gradientCoverageView Ausgang auf eine Ansicht, die die gesamte Fläche des Gradienten so bedeckt, eine Ansicht, die alle fünf der Etiketten abdeckt. Dies könnte die Supervision der Labels sein, oder es könnte nur eine versteckte Ansicht sein, die Sie eingerichtet haben, um (unsichtbar) den gleichen Bereich zu füllen.

Setzen Sie startColor auf violett und endColor auf orange.

Wir werden den Verlauf gefüllten Text (in unserem drawTextInRect: gekröpft) in drei Schritten ziehen:

  1. Anruf super ziehen Sie einfach den Text normal.

  2. Legen Sie den Grafikkontext-Mischmodus kCGBlendModeSourceIn fest. Dieser Mischmodus weist Core Graphics an, nur dort zu zeichnen, wo der Kontext bereits gezeichnet wurde, und zu überschreiben, was dort gezeichnet wurde. So behandelt Core Graphics den von super gezeichneten Text als Maske.

  3. Zeichnen den Gradienten mit dem Startpunkt an der Oberseite der Abdeckung Ansicht und den Endpunkt auf der Unterseite der Abdeckung Ansicht, nicht am oberen und unteren Rande des aktuellen Etiketts. So ist die Steigung Ansicht, die die gesamte Abdeckung erstreckt, ist aber maskiert nur zu zeigen, wo der Text des aktuellen Etikett in Schritt gezogen wurde 1.

Hier ist die Umsetzung:

@implementation GradientLabel 

- (void)drawTextInRect:(CGRect)rect { 
    [super drawTextInRect:rect]; 

    CGContextRef gc = UIGraphicsGetCurrentContext(); 
    NSArray *colors = @[(__bridge id)self.startColor.CGColor, (__bridge id)self.endColor.CGColor]; 
    CGGradientRef gradient = CGGradientCreateWithColors(CGBitmapContextGetColorSpace(gc), (__bridge CFArrayRef)colors, NULL); 

    UIView *coverageView = self.gradientCoverageView ?: self; 
    CGRect coverageRect = [coverageView convertRect:coverageView.bounds toView:self]; 
    CGPoint startPoint = coverageRect.origin; 
    CGPoint endPoint = { coverageRect.origin.x, CGRectGetMaxY(coverageRect) }; 

    CGContextSaveGState(gc); { 
     CGContextSetBlendMode(gc, kCGBlendModeSourceIn); 
     CGContextDrawLinearGradient(gc, gradient, startPoint, endPoint, 0); 
    } CGContextRestoreGState(gc); 

    CGGradientRelease(gradient); 
} 

@end 

Hier ist das Layout in meinem Drehbuch:

storyboard

Für alle fünf der GradientLabel Fällen stelle ich die startColor pur Ple und die endColor zu Orange und ich schloss die gradientCoverageView Steckdose an die umschließende Stapelansicht.

+0

Vielen Dank für die Bereitstellung der Hardcore-Methode. : D – Vulkan

Verwandte Themen