Utwórz UIImage z jednolitym kolorem w Swift

140

Chcę programowo utworzyć UIImage wypełniony jednolitym kolorem. Czy ktoś ma pomysł, jak to zrobić w Swift?

Henry Pham
źródło
UIImagenie ma -initWithSize:andColor:metody, ale NSImagedziała w systemie OS X. Czy używasz do tego niestandardowej biblioteki lub kategorii?
ttarik
Przepraszam, to prawda, że ​​użyłem go w kategorii (patrząc na stary projekt). Po prostu edytuj moje pytanie.
Henry Pham

Odpowiedzi:

194

Innym fajnym rozwiązaniem, kompatybilnym ze Swift 2.2 , jest utworzenie kolejnego konstruktora w UIImage w ten sposób:

public extension UIImage {
    public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
        let rect = CGRect(origin: .zero, size: size)
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
        color.setFill()
        UIRectFill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        guard let cgImage = image?.CGImage else { return nil }
        self.init(CGImage: cgImage)
    }  
}

W ten sposób możesz stworzyć niestandardowy kolorowy obraz w następujący sposób:

let redImage = UIImage(color: .redColor())

Lub opcjonalnie utwórz obraz o niestandardowym rozmiarze:

let redImage200x200 = UIImage(color: .redColor(), size: CGSize(width: 200, height: 200))

Swift 3.0

public extension UIImage {
  public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
    let rect = CGRect(origin: .zero, size: size)
    UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
    color.setFill()
    UIRectFill(rect)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    guard let cgImage = image?.cgImage else { return nil }
    self.init(cgImage: cgImage)
  }
}
Luca Davanzo
źródło
1
jeśli chcesz stworzyć obraz o rozmiarze 1x, zacznij od tego kodu UIGraphicsBeginImageContextWithOptions(rect.size, true, 1.0) ref: developer.apple.com/library/ios/documentation/UIKit/Reference/ ...
nahung89
3
Jak możemy sprawić, by te obrazy były zaokrąglone?
Umair Afzal,
Dlaczego nie możemy po prostu wrócić image? Po co to robić? self.init(cgImage: cgImage)
Andrey Gagan
@AndreyGagan AFAIK, nie możesz "zastąpić" self nowo utworzonym UIImagew konstruktorze, ale UIImage.init(cgImage: )zamiast tego możesz połączyć się za pomocą konstruktora.
Alnitak
2
Obraz nie jest tworzony w odpowiedniej skali. Np. Jeśli rozmiar wynosi 1x1, obraz 2x2 jest zwracany, gdy skala głównego ekranu wynosi 2,0. Powinieneś zadzwonićself.init(cgImage: cgImage, scale: image!.scale, orientation: image!.imageOrientation)
Marián Černý
92

Oto inna opcja. Myślę, że chciałeś mieć dokładny obiekt UIImage.

func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
    let rect = CGRectMake(0, 0, size.width, size.height)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

Umieść to w swoim kodzie Swift i zadzwoń

Swift 3.1:

func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
    let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image
}
anthonyliao
źródło
Myślę, że nie istnieje metoda UIRectMake(0, 0, size.width, size.height), to wydaje się być prawidłowa: CGRectMake(0, 0, size.width, size.height).
Henry Pham
1
Ogólnie rzecz biorąc, spróbuj użyć letzamiast varniezmiennych zmiennych; tutaj wygląda na to, że ani rectani nie imagepowinien używać vardeklaracji.
Zorayr
1
Jak możemy sprawić, by te obrazy były zaokrąglone?
Umair Afzal,
83

Wersja Swift 4:

extension UIColor {
    func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { rendererContext in
            self.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
    }
}

Stosowanie:

let image0 = UIColor.orange.image(CGSize(width: 128, height: 128))
let image1 = UIColor.yellow.image()
neoneye
źródło
3
Podoba mi się, że utworzony obraz nie jest opcjonalny
jlukanta
1
Bardzo mi się to podoba, dla mnie sensowne jest, aby rozszerzenie pochodziło z koloru, a nie z obrazu.
quemeful
1
(⚠️ iOS 10 lub nowszy). Przy okazji miła i czysta odpowiedź.
od
19

Czystszym podejściem byłoby hermetyzowanie logiki wewnątrz UIImagerozszerzenia:

import UIKit

extension UIImage {
  class func imageWithColor(color: UIColor) -> UIImage {
    let rect: CGRect = CGRectMake(0, 0, 1, 1)
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 1), false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
  }
}

Teraz konsument może zadzwonić, UIImage.imageWithColor(UIColor.blackColor())aby stworzyć obraz z czarnym tłem.

Zorayr
źródło
Jak możemy sprawić, by te obrazy były zaokrąglone?
Umair Afzal,
10
class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        imageView.backgroundColor = UIColor.redColor()
    }
}

Podobna metoda, jeśli chcesz samodzielnie narysować obraz, a nie podłączenie go przez IBOutlet.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var frame = CGRectMake(100,100,100,100)
        var imageView2 = UIImageView(frame: frame)
        imageView2.backgroundColor = UIColor.redColor()
        self.view.addSubview(imageView2)
    }
}

Trzecia metoda zapożyczania od Anthonyliao. Trochę bardziej skomplikowane:

class ViewController: UIViewController {

    func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        color.setFill()
        UIRectFill(CGRectMake(0, 0, 100, 100))
        var image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        var imageView = UIImageView(frame: CGRectMake(100,100,100,100))
        let screenImage = getImageWithColor(UIColor.redColor(), size: CGSize(width: 100, height: 100))
        imageView.image = screenImage
        self.view.addSubview(imageView)
    }
}
Steve Rosenberg
źródło
2
To prawdopodobnie osiąga taki efekt, że PO chciała, ale to nic nie warte, że mieli metodę, aby utworzyć UIImage, nie ustawić UIImageView.
ttarik
Twoja druga metoda nadal tworzy widok obrazu, a nie obraz, na co zwracał uwagę @ ev0lution.
rdelmar
edycja 3 załączona. Teraz mamy kilka sposobów. Ostatni z UIImageView.
Steve Rosenberg
1
Metoda getImageWithColor(color: UIColor, size: CGSize) -> UIImagejest wystarczająca jako odpowiedź, ponieważ myślę, że nie wszyscy będą używać tego razem z UIImageView
Henry Pham
Jak możemy sprawić, by te obrazy były zaokrąglone?
Umair Afzal,
9

Drobne poprawki do doskonałej odpowiedzi @ neoneye, dzięki którym kod wywołujący nie musi tworzyć CGSize i zmienił nazwę, aby nie kolidowała z wieloma innymi:

Szybki 4

extension UIColor {
    func imageWithColor(width: Int, height: Int) -> UIImage {
        let size = CGSize(width: width, height: height)
        return UIGraphicsImageRenderer(size: size).image { rendererContext in
            self.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
    }
}
rysował..
źródło
8

Możesz użyć nowego interfejsu API UIGraphicsImageRenderer na iOS 10 .

Oto rozszerzenie UIColor w Swift 3.1

extension UIColor {
func getImage(size: CGSize) -> UIImage {
    let renderer = UIGraphicsImageRenderer(size: size)
    return renderer.image(actions: { rendererContext in
        self.setFill()
        rendererContext.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
    })
}}
Moustafa Baalbaki
źródło
6

Dobrym sposobem jest posiadanie takiej obliczonej właściwości:

extension UIColor {
    var imageRepresentation : UIImage {
      let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)
      UIGraphicsBeginImageContext(rect.size)
      let context = UIGraphicsGetCurrentContext()

      context?.setFillColor(self.cgColor)
      context?.fill(rect)

      let image = UIGraphicsGetImageFromCurrentImageContext()
      UIGraphicsEndImageContext()

    return image!
  }
}

Stosowanie:

let redImage = UIColor.red.imageRepresentation
iOSGeek
źródło
Myślę, że niektóre odpowiedzi są trochę mylące. W większości przypadków będziesz musiał określić rozmiar obrazu, a nie konkretny przypadek (np. 1x1). Ale to miłe podejście.
Henry Pham
4

Wersja Swift 3 @anthonyliao Zaakceptowana odpowiedź:

class func getImageWithColor(color: UIColor, size: CGSize) -> UIImage
{
    let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: size.width, height: size.height))
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image
}
Ayman Ibrahim
źródło
0

Prosty z zaokrąglonymi rogami

extension UIImage {
convenience init?(color: UIColor) {
    let rect = CGRect(x: 0, y: 0, width: 10, height: 2)
    UIGraphicsBeginImageContextWithOptions(CGSize(width: 10, height: 2), false, 0)
    let bezierPath = UIBezierPath(roundedRect: rect, cornerRadius: 8)
    color.setFill()
    bezierPath.fill()
    let image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    guard  let cgImage = image.cgImage else {
        return nil
    }
    self.init(cgImage: cgImage)
}

}

droid
źródło