Erhalten Sie hellere und dunklere Farbvariationen für eine bestimmte UIColor

69

Wie kann man in Swift verschiedene hellere und dunklere Variationen einer bestimmten UIColor erhalten?

Geben Sie hier die Bildbeschreibung ein

Stephen
quelle
1
Die Titelfrage ist ziemlich trivial und erlaubt unterschiedliche Lösungen. Sie können auch eine Funktion anstelle von zwei verwenden, indem Sie den negativen Eingabeparameter verwenden
Shadow Of
Hier wurden verschiedene Techniken vorgeschlagen. Stackoverflow.com/questions/11598043/… , es gibt auch Antworten in Swift.
Martin R
@ ShadowOf aktualisiert, danke für die Eingabe
Stephen
Swift - 4.0 Klicken Sie auf Hase für Antwort
Ramchandra n
Diese Antwort war bereits verfügbar, als Sie Ihre Frage gestellt haben. Im Allgemeinen denke ich, dass diese und die andere Frage sehr ähnlich sind, wenn nicht doppelt.
Gog

Antworten:

146

Aktualisiert

Verwendung unter UIColor Extension:

extension UIColor {

    func lighter(by percentage: CGFloat = 30.0) -> UIColor? {
        return self.adjust(by: abs(percentage) )
    }

    func darker(by percentage: CGFloat = 30.0) -> UIColor? {
        return self.adjust(by: -1 * abs(percentage) )
    }

    func adjust(by percentage: CGFloat = 30.0) -> UIColor? {
        var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
        if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
            return UIColor(red: min(red + percentage/100, 1.0),
                           green: min(green + percentage/100, 1.0),
                           blue: min(blue + percentage/100, 1.0),
                           alpha: alpha)
        } else {
            return nil
        }
    }
}

Verwendung:

let color = UIColor(red:0.96, green:0.54, blue:0.10, alpha:1.0)
color.lighter(30) // returns lighter color by 30%
color.darker(30) // returns darker color by 30%

Anstelle von .lighter()und .darker()können Sie .adjust()positive Werte für die Aufhellung und negative Werte für die Verdunkelung verwenden

color.adjust(-30) // 30% darker color
color.adjust(30) // 30% lighter color

Ausgabe:

Geben Sie hier die Bildbeschreibung ein

Stephen
quelle
3
Sie ändern alle Komponenten um denselben Wert, anstatt sie proportional zu ändern. Sehen Sie, wie Orange gelb wird, wenn Sie es heller machen.
Martin R
Das proportionale Hinzufügen von Werten ist nicht korrekt. Versuchen Sie diese Farbe UIColor (rot: 0,89, grün: 0,28, blau: 0,00, alpha: 1,0)
Stephen
4
Das Hinzufügen des gleichen Werts zu allen Komponenten ist jedoch auch nicht korrekt, sondern ändert die Farbe. Schauen Sie sich die verschiedenen Antworten auf stackoverflow.com/questions/11598043/… an, bei denen die Helligkeit in der HSB-Darstellung angepasst wird.
Martin R
@MartinR Ich habe deine und meine Funktion ausgeführt, beide Ausgänge sind gleich (orange ist nicht gelb geworden ;-)). Allerdings muss ich die Fähigkeiten verbessern, um den Code zu reduzieren. Ich hätte vermeiden sollen, in RGB-Werte zu konvertieren und Logik in einer einzigen Funktion zu schreiben. wird den Code aktualisieren
Stephen
Ich glaube für schwarze Farbe heller, gibt grüne Farbe zurück
NNikN
41

Ich möchte eine andere Version mit Helligkeit und Sättigung anstelle von RGB bereitstellen

extension UIColor {
  /**
   Create a ligher color
   */
  func lighter(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: abs(percentage))
  }

  /**
   Create a darker color
   */
  func darker(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: -abs(percentage))
  }

  /**
   Try to increase brightness or decrease saturation
   */
  func adjustBrightness(by percentage: CGFloat = 30.0) -> UIColor {
    var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
    if self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) {
      if b < 1.0 {
        let newB: CGFloat = max(min(b + (percentage/100.0)*b, 1.0), 0.0)
        return UIColor(hue: h, saturation: s, brightness: newB, alpha: a)
      } else {
        let newS: CGFloat = min(max(s - (percentage/100.0)*s, 0.0), 1.0)
        return UIColor(hue: h, saturation: newS, brightness: b, alpha: a)
      }
    }
    return self
  }
}
Tran Quan
quelle
4
Ich denke, das ist besser als die RGB-Werte zu
ändern
Denken Sie nicht, dass dies funktioniert, wenn die Sättigung 0 und die Helligkeit 1,0 beträgt. IE weiß. In diesem Fall erhalten Sie eine unveränderte Sättigung.
Verlorene Übersetzung
(Sie können Weiß nicht aufhellen.) Dies ist der richtige Ansatz. Die RGB-Antworten sind auf vielen Ebenen völlig falsch.
Fattie
8

Um jeden zu retten, der tippt, ist die einfache praktische Version einfach

extension UIColor {

    var darker: UIColor {

    var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0

        guard self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) else {
            print("** some problem demuxing the color")
            return .gray
        }

        let nudged = b * 0.5

        return UIColor(hue: h, saturation: s, brightness: nudged, alpha: a)
    }
}

benutze wie

something.color = .yellow.darker

oder

backgroundColor = backgroundColor.darker

Bei einem großen Projekt .................

Sie sollten auf jeden Fall das Muster von Apple erweitern:

.withAlphaComponent(_ alpha: CGFloat)

So haben:

.withBrightnessComponent(_ alpha: CGFloat)

und deutlich

.withBrightnessComponentAdjustedBy(percentage: CGFloat)

und / oder

.withBrightnessComponentMultipliedBy(factor: CGFloat)
Fattie
quelle
6

SwiftUI: Farbe - iOS 14 / macOS 10.16

extension Color {
    public func lighter(by amount: CGFloat = 0.2) -> Self { Self(UIColor(self).lighter(by: amount)) }
    public func darker(by amount: CGFloat = 0.2) -> Self { Self(UIColor(self).darker(by: amount)) }
}

Erfordert eine der folgenden (oder beide) Optionen für iOS oder (und) macOS


AppKit: NSColor

extension NSColor {
    func mix(with color: NSColor, amount: CGFloat) -> Self {
        var red1: CGFloat = 0
        var green1: CGFloat = 0
        var blue1: CGFloat = 0
        var alpha1: CGFloat = 0

        var red2: CGFloat = 0
        var green2: CGFloat = 0
        var blue2: CGFloat = 0
        var alpha2: CGFloat = 0

        getRed(&red1, green: &green1, blue: &blue1, alpha: &alpha1)
        color.getRed(&red2, green: &green2, blue: &blue2, alpha: &alpha2)

        return Self(
            red: red1 * CGFloat(1.0 - amount) + red2 * amount,
            green: green1 * CGFloat(1.0 - amount) + green2 * amount,
            blue: blue1 * CGFloat(1.0 - amount) + blue2 * amount,
            alpha: alpha1
        )
    }

    func lighter(by amount: CGFloat = 0.2) -> Self { mix(with: .white, amount: amount) }
    func darker(by amount: CGFloat = 0.2) -> Self { mix(with: .black, amount: amount) }
}

UIKit: UIColor

extension UIColor {
    func mix(with color: UIColor, amount: CGFloat) -> Self {
        var red1: CGFloat = 0
        var green1: CGFloat = 0
        var blue1: CGFloat = 0
        var alpha1: CGFloat = 0

        var red2: CGFloat = 0
        var green2: CGFloat = 0
        var blue2: CGFloat = 0
        var alpha2: CGFloat = 0

        getRed(&red1, green: &green1, blue: &blue1, alpha: &alpha1)
        color.getRed(&red2, green: &green2, blue: &blue2, alpha: &alpha2)

        return Self(
            red: red1 * CGFloat(1.0 - amount) + red2 * amount,
            green: green1 * CGFloat(1.0 - amount) + green2 * amount,
            blue: blue1 * CGFloat(1.0 - amount) + blue2 * amount,
            alpha: alpha1
        )
    }

    func lighter(by amount: CGFloat = 0.2) -> Self { mix(with: .white, amount: amount) }
    func darker(by amount: CGFloat = 0.2) -> Self { mix(with: .black, amount: amount) }
}
Mojtaba Hosseini
quelle
Eivoullla Mojtaba! 👏
Ahmadreza
4

Für Swift 5.0:

extension UIColor {

func lighter(by percentage: CGFloat = 10.0) -> UIColor {
    return self.adjust(by: abs(percentage))
}

func darker(by percentage: CGFloat = 10.0) -> UIColor {
    return self.adjust(by: -abs(percentage))
}

func adjust(by percentage: CGFloat) -> UIColor {
    var alpha, hue, saturation, brightness, red, green, blue, white : CGFloat
    (alpha, hue, saturation, brightness, red, green, blue, white) = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

    let multiplier = percentage / 100.0

    if self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
        let newBrightness: CGFloat = max(min(brightness + multiplier*brightness, 1.0), 0.0)
        return UIColor(hue: hue, saturation: saturation, brightness: newBrightness, alpha: alpha)
    }
    else if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
        let newRed: CGFloat = min(max(red + multiplier*red, 0.0), 1.0)
        let newGreen: CGFloat = min(max(green + multiplier*green, 0.0), 1.0)
        let newBlue: CGFloat = min(max(blue + multiplier*blue, 0.0), 1.0)
        return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
    }
    else if self.getWhite(&white, alpha: &alpha) {
        let newWhite: CGFloat = (white + multiplier*white)
        return UIColor(white: newWhite, alpha: alpha)
    }

    return self
    }
}
BSK-Team
quelle
3

Da ich SwiftUI in meinem aktuellen Projekt verwende, habe ich die beste Antwort von Stephen angepasst. Getestet mit Xcode 12.0, SwiftUI 2 und iOS 14.0

extension Color {
    var components: (red: CGFloat, green: CGFloat, blue: CGFloat, opacity: CGFloat) {
        #if canImport(UIKit)
        typealias NativeColor = UIColor
        #elseif canImport(AppKit)
        typealias NativeColor = NSColor
        #endif

        var r: CGFloat = 0
        var g: CGFloat = 0
        var b: CGFloat = 0
        var o: CGFloat = 0

        guard NativeColor(self).getRed(&r, green: &g, blue: &b, alpha: &o) else {
            return (0, 0, 0, 0)
        }
        return (r, g, b, o)
    }
    
    func lighter(by percentage: CGFloat = 30.0) -> Color {
        return self.adjust(by: abs(percentage) )
    }

    func darker(by percentage: CGFloat = 30.0) -> Color {
        return self.adjust(by: -1 * abs(percentage) )
    }

    func adjust(by percentage: CGFloat = 30.0) -> Color {
        return Color(red: min(Double(self.components.red + percentage/100), 1.0),
                     green: min(Double(self.components.green + percentage/100), 1.0),
                     blue: min(Double(self.components.blue + percentage/100), 1.0),
                     opacity: Double(self.components.opacity))
    }
}
Hikeland
quelle
2

Version mit Änderung der RGB-Werte

Hier habe ich eine einfache UIColorErweiterung eingefügt, die auf früheren Antworten basiert. Es funktioniert perfekt für mich.

Unten Demo:

Farbdemo

Farbmanipulationscode

public extension UIColor {

    /**
     Create a lighter color
     */
    public func lighter(by percentage: CGFloat = 30.0) -> UIColor {
        return self.adjustBrightness(by: abs(percentage))
    }

    /**
     Create a darker color
     */
    public func darker(by percentage: CGFloat = 30.0) -> UIColor {
        return self.adjustBrightness(by: -abs(percentage))
    }

    /**
     Changing R, G, B values
     */

    func adjustBrightness(by percentage: CGFloat = 30.0) -> UIColor {

        var red: CGFloat = 0.0
        var green: CGFloat = 0.0
        var blue: CGFloat = 0.0
        var alpha: CGFloat = 0.0

        if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {

            let pFactor = (100.0 + percentage) / 100.0

            let newRed = (red*pFactor).clamped(to: 0.0 ... 1.0)
            let newGreen = (green*pFactor).clamped(to: 0.0 ... 1.0)
            let newBlue = (blue*pFactor).clamped(to: 0.0 ... 1.0)

            return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
        }

        return self
    }
}

Klemmfunktion Erweiterung, um Werte zwischen min und max zu halten.

extension Comparable {

    func clamped(to range: ClosedRange<Self>) -> Self {

        if self > range.upperBound {
            return range.upperBound
        } else if self < range.lowerBound {
            return range.lowerBound
        } else {
            return self
        }
    }
}
lukszar
quelle
1

Die Antwort von Kenji-Tran funktioniert einwandfrei, solange Ihre Ausgangsfarbe nicht schwarz ist (Helligkeitswert 0). Durch Hinzufügen einiger zusätzlicher Codezeilen können Sie Schwarz auch "heller" machen (dh es auf einen Graustufen- oder Farbwert aufhellen).

Hinweis: Ich konnte diese Änderung nicht mit einem Edit hinzufügen und darf die Antwort von Kenji-Tran aufgrund meines Vertreters "New Boy" nicht kommentieren. Daher habe ich bis dahin keine andere Möglichkeit gefunden, mein Wissen über SO zu teilen eine neue Antwort posten. Ich hoffe das ist okay.

extension UIColor {
  /**
   Create a ligher color
   */
  func lighter(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: abs(percentage))
  }

  /**
   Create a darker color
   */
  func darker(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: -abs(percentage))
  }

  /**
   Try to increase brightness or decrease saturation
   */
  func adjustBrightness(by percentage: CGFloat = 30.0) -> UIColor {
    var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
    if self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) {
      if b < 1.0 {
        /**
         Below is the new part, which makes the code work with black as well as colors
        */
        let newB: CGFloat
        if b == 0.0 {
            newB = max(min(b + percentage/100, 1.0), 0.0)
        } else {
            newB = max(min(b + (percentage/100.0)*b, 1.0), 0,0)
        }
        return UIColor(hue: h, saturation: s, brightness: newB, alpha: a)
      } else {
        let newS: CGFloat = min(max(s - (percentage/100.0)*s, 0.0), 1.0)
        return UIColor(hue: h, saturation: newS, brightness: b, alpha: a)
      }
    }
    return self
  }
}
ChrisDL
quelle
Vielen Dank für den Hinweis auf den fehlenden Fall (y). Dürfte ich eine Frage stellen? Warum ist es so b == 0.0 && s == 0.0? Ich dachte, nur mehr Fall zu wollen, b == 0reicht aus, um das Problem zu lösen. Denn wenn b is 0 and s > 0ja, kann Ihr Code die Farbe immer noch nicht heller machen?
Tran Quan
Gute Frage. Es ist ein Fehler. Ich habe den Code behoben. Der Grund, warum ich nachgesehen habe, s == 0war, dass ich wollte, dass es für Schwarz bis Graustufen funktioniert. Aber natürlich s == 0funktioniert es ohne das für jede Farbe mit einer Helligkeit von Null. Vielen Dank.
ChrisDL
0

Mit der Funktion lukszar clampled habe ich diese Funktion für die UIColor-Erweiterung unter Verwendung realer Anteile der RGB-Werte geschrieben. Ich hoffe es ist hilfreich

public extension UIColor {

  public func lighter(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: abs(percentage))
  }

  public func darker(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: -abs(percentage))
  }

  func adjustBrightness(by percentage: CGFloat = 30.0) -> UIColor {

    let ratio = percentage/100

    var red:   CGFloat = 0.0
    var green: CGFloat = 0.0
    var blue:  CGFloat = 0.0
    var alpha: CGFloat = 0.0

    if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
      let newRed =   (red   + ((ratio < 0) ? red   * ratio : (1 - red)   * ratio)).clamped(to: 0.0 ... 1.0)
      let newGreen = (green + ((ratio < 0) ? green * ratio : (1 - green) * ratio)).clamped(to: 0.0 ... 1.0)
      let newBlue =  (blue  + ((ratio < 0) ? blue  * ratio : (1 - blue)  * ratio)).clamped(to: 0.0 ... 1.0)
      return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
    }
    return self
  }
}
Oscar
quelle
0

Geben Sie hier die Bildbeschreibung ein

Das folgende Codebeispiel zeigt, wie Sie einen helleren und dunkleren Farbton einer bestimmten Farbe erzielen können, der in Anwendungen mit dynamischen Themen nützlich ist

Für dunklere Farbe

+ (UIColor *)darkerColorForColor:(UIColor *)c
{
CGFloat r, g, b, a;
    if ([c getRed:&r green:&g blue:&b alpha:&a])
return [UIColor colorWithRed:MAX(r - 0.2, 0.0)
                               green:MAX(g - 0.2, 0.0)
                                blue:MAX(b - 0.2, 0.0)
return nil; 
}

Für hellere Farben

+ (UIColor *)lighterColorForColor:(UIColor *)c
{
CGFloat r, g, b, a;
    if ([c getRed:&r green:&g blue:&b alpha:&a])
return [UIColor colorWithRed:MIN(r + 0.2, 1.0)
                       green:MIN(g + 0.2, 1.0)
                        blue:MIN(b + 0.2, 1.0)
alpha:a];
return nil;
}

Mr.Javed Multani
quelle
0

Swift 4-Version, die RGBA, HSBA und WB unterstützt (Graustufen)

Hier ist eine Variation der Antwort von TranQuan, die auch Graustufenfarben wie .whiteund unterstützt .black. (Hinweis: Ich habe die Sättigungsanpassung entfernt, weil ich nicht dachte, dass sie zu einer einfachen Funktion wie dieser gehört.)

extension UIColor {
    /**
     Create a ligher color
     */
    func lighter(by percentage: CGFloat = 10.0) -> UIColor {
        return self.adjustBrightness(by: abs(percentage))
    }

    /**
     Create a darker color
     */
    func darker(by percentage: CGFloat = 10.0) -> UIColor {
        return self.adjustBrightness(by: -abs(percentage))
    }

    /**
     Try to adjust brightness and falls back to adjusting colors if necessary
     */
    func adjustBrightness(by percentage: CGFloat) -> UIColor {
        var alpha, hue, saturation, brightness, red, green, blue, white : CGFloat
        (alpha, hue, saturation, brightness, red, green, blue, white) = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

        let multiplier = percentage / 100.0

        if self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
            let newBrightness: CGFloat = max(min(brightness + multiplier*brightness, 1.0), 0.0)
            return UIColor(hue: hue, saturation: saturation, brightness: newBrightness, alpha: alpha)
        }
        else if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
            let newRed: CGFloat = min(max(red + multiplier*red, 0.0), 1.0)
            let newGreen: CGFloat = min(max(green + multiplier*green, 0.0), 1.0)
            let newBlue: CGFloat = min(max(blue + multiplier*blue, 0.0), 1.0)
            return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
        }
        else if self.getWhite(&white, alpha: &alpha) {
            let newWhite: CGFloat = (white + multiplier*white)
            return UIColor(white: newWhite, alpha: alpha)
        }

        return self
    }
}
Warpling
quelle