iadgotstacked
iadgotstacked

Reputation: 83

Swift 3 draw uiimage programmatically

I don't have experience in Core Graphics but I need to draw a dynamic uiimage that look like these:

left

whole

(Actually I want the grey area to be clear. So the red color will look like floating)

This is the code I tried:

public extension UIImage {

    public convenience init?(color: UIColor, size: CGSize = CGSize(width: 27, height: 5), isWhole: Bool = true) {
        let totalHeight: CGFloat = 5.0
        let topRectHeight: CGFloat = 1.0

        //if (isWhole) {
        let topRect = CGRect(origin: .zero, size: CGSize(width: size.width, height: topRectHeight))
        UIGraphicsBeginImageContextWithOptions(topRect.size, false, 0.0)
        color.setFill()
        UIRectFill(topRect)

        let bottomRect = CGRect(origin: CGPoint(x: 0, y: topRectHeight), size: CGSize(width: size.width, height: totalHeight - topRectHeight))
        UIGraphicsBeginImageContextWithOptions(bottomRect.size, false, 0.0)
        UIColor.blue.setFill()
        UIRectFill(bottomRect)

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

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

Upvotes: 2

Views: 5607

Answers (3)

Svetoslav Bramchev
Svetoslav Bramchev

Reputation: 433

Here is example you can have first image if you set isWhole property to false and have second image if you set it to true. You can paste this code in viewDidLoad to test and play with it.

    var isWhole = false
    UIGraphicsBeginImageContextWithOptions(CGSize.init(width: 27, height: 5), false,0.0)
    var context = UIGraphicsGetCurrentContext()
    context?.setFillColor(UIColor.red.cgColor)
    if(context != nil){
        if(isWhole){
            context?.fill(CGRect(x: 0, y: 0, width: 27, height: 2.5))
        }
        else{
            context?.fill(CGRect(x: 0, y: 0, width: 13.5, height: 2.5))
        }
        context?.setFillColor(UIColor.gray.cgColor)
        context?.fill(CGRect(x: 0, y: 2.5, width: 27, height: 2.5))
    }


    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    var imageView = UIImageView(frame: CGRect(x: 100, y: 200, width: 27, height: 5))
    imageView.image = newImage
    self.view.addSubview(imageView)
    UIGraphicsEndImageContext()

If you need your red rectangle to be with rounder corners just change fill(rect:CGRect) with path like this:

    if(isWhole){
        context?.addPath(CGPath(roundedRect: CGRect(x: 0, y: 0, width: 27, height: 2.5), cornerWidth: 1, cornerHeight: 1, transform: nil))
        context?.fillPath()
    }

Upvotes: 1

user7014451
user7014451

Reputation:

I know you said in your comments that you can't use UIViews, but what you want "looks" easily done through views. Why not do that, then simply turn it into a UIImage?

override func viewDidLoad() {
    super.viewDidLoad()

    let imageContainer = UIView(frame: CGRect(x: 30, y: 40, width: 110, height: 60))
    imageContainer.backgroundColor = view.backgroundColor
    view.addSubview(imageContainer)

    let redView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
    redView.backgroundColor = UIColor.red
    let grayView = UIView(frame: CGRect(x: 10, y: 30, width: 100, height: 30))
    grayView.backgroundColor = UIColor.gray
    imageContainer.addSubview(redView)
    imageContainer.addSubview(grayView)

    let imageView = UIImageView(frame: CGRect(x: 100, y: 140, width: 200, height: 200))
    imageView.contentMode = .scaleAspectFit
    imageView.image = createImage(imageContainer)

    view.addSubview(imageView)
}

func createImage(_ view: UIView) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(
        CGSize(width: view.frame.width, height: view.frame.height), true, 1)
    view.layer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image!
}

Upvotes: 1

genghiskhan
genghiskhan

Reputation: 1149

I'd recommend creating two paths in the first context that you create, i.e.

let topPath = UIBezierPath(rect: topRect)
color.setFill()
topPath.fill()

let bottomPath = UIBezierPath(rect: bottomRect)
UIColor.blue.setFill()
bottomPath.fill()

Then you can get the image from the current context.

Upvotes: 0

Related Questions