Crie UIImage com cores sólidas no Swift

140

Quero criar programaticamente uma UIImage preenchida por uma cor sólida. Alguém tem uma idéia de como fazer isso no Swift?

Henry Pham
fonte
UIImagenão possui um -initWithSize:andColor:método, mas NSImagepossui no OS X. Você está usando uma biblioteca ou categoria personalizada para isso?
Ttarik 24/10/14
Desculpe, é verdade que eu o usei em uma categoria (olhando para um projeto antigo). Apenas edite minha pergunta.
Henry Pham

Respostas:

194

Outra solução interessante, compatível com Swift 2.2 , é criar outro construtor no UIImage, desta maneira:

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

Dessa maneira, você pode criar a imagem colorida personalizada da seguinte maneira:

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

Ou, opcionalmente, crie a imagem com um tamanho personalizado:

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
fonte
1
se você deseja criar uma imagem com tamanho 1x, comece com este código UIGraphicsBeginImageContextWithOptions(rect.size, true, 1.0) ref: developer.apple.com/library/ios/documentation/UIKit/Reference/…
nahung89
3
Como podemos tornar essas imagens mais arredondadas?
Umair Afzal
Por que não podemos simplesmente voltar image? Por que precisa fazer isso? self.init(cgImage: cgImage)
precisa saber é o seguinte
@AndreyGagan AFAIK, você não pode "substituir" o eu pelo recém-criado UIImageem um construtor, mas pode encadear através do UIImage.init(cgImage: )construtor.
Alnitak
2
A imagem não é criada com a escala adequada. Por exemplo, quando o tamanho é 1x1, uma imagem 2x2 é retornada quando a escala da tela principal é 2,0. Você deve ligarself.init(cgImage: cgImage, scale: image!.scale, orientation: image!.imageOrientation)
Marián Černý
92

Aqui está outra opção. Eu acredito que você queria um objeto UIImage exato.

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
}

Coloque isso no seu código Swift e chame-o

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
fonte
Eu acho que não há nenhum método UIRectMake(0, 0, size.width, size.height), este parece ser o correto: CGRectMake(0, 0, size.width, size.height).
Henry Pham
1
Geralmente, tente usar em letvez de varpara variáveis ​​imutáveis; aqui parece que rectnem imagedeveria estar usando vardeclaração.
Zorayr
1
Como podemos tornar essas imagens mais arredondadas?
Umair Afzal
83

Versão 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))
        }
    }
}

Uso:

let image0 = UIColor.orange.image(CGSize(width: 128, height: 128))
let image1 = UIColor.yellow.image()
neoneye
fonte
3
Eu gosto que a imagem criada não seja opcional
jlukanta
1
Eu gosto muito disso, para mim faz muito sentido que a extensão seja da cor e não da imagem.
quemeful 12/07/19
1
(IOS️ iOS 10 ou mais recente). Resposta agradável e limpa entre.
Frouo 28/10/19
19

Uma abordagem mais limpa seria encapsular a lógica dentro de uma UIImageextensão:

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

Agora o consumidor pode ligar UIImage.imageWithColor(UIColor.blackColor())para criar uma imagem com fundo preto.

Zorayr
fonte
Como podemos tornar essas imagens mais arredondadas?
Umair Afzal
10
class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        imageView.backgroundColor = UIColor.redColor()
    }
}

Método semelhante, se você quiser desenhar a imagem, em vez de conectar uma via 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)
    }
}

Terceiro método emprestado de anthonyliao. Um pouco mais complicado:

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
fonte
2
Este , provavelmente, atinge o efeito que a OP queria, mas vale a pena nada que eles tinham um método para criar um UIImage, não para definir um UIImageView.
ttarik
Seu segundo método ainda cria uma visualização de imagem, não uma imagem, que é o que @ ev0lution estava apontando.
Rdelmar # 24/14
editar 3 anexado. Agora temos várias maneiras. Final com um UIImageView.
9788 Steve Rosenberg #
1
O método getImageWithColor(color: UIColor, size: CGSize) -> UIImageé o suficiente como a resposta, como eu acho que nem todo mundo vai usar isso em conjunto com um UIImageView
Henry Pham
Como podemos tornar essas imagens mais arredondadas?
Umair Afzal
9

Um pequeno ajuste na excelente resposta de @ neoneye, permitindo que o código de chamada não precise criar o CGSize e alterou o nome para não colidir com muitos outros:

Swift 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))
        }
    }
}
desenhou..
fonte
8

Você pode usar a nova API do iOS 10 UIGraphicsImageRenderer .

Aqui está uma extensão no UIColor no 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
fonte
6

Uma boa maneira é ter uma propriedade computada como esta:

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!
  }
}

Uso:

let redImage = UIColor.red.imageRepresentation
iOSGeek
fonte
Eu acho que algumas respostas aqui são um pouco enganadoras. Na maioria das vezes, você precisará especificar o tamanho da imagem, não um caso específico (como 1x1). Mas esta é uma boa abordagem.
Henry Pham
4

Versão Swift 3 de @anthonyliao Resposta aceita:

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
fonte
0

Reto com cantos arredondados

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

}

andróide
fonte