2

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)
    }
3
  • Do you need images or could it be UIViews? Commented Jul 10, 2017 at 15:30
  • need to be uiimage. as the library function im calling needs uiimage as input. Commented Jul 10, 2017 at 15:32
  • I'm adding a new answer. I know you've accepted one already, but this may be a good alternative. It turns any UIView into a UIImage. Commented Jul 10, 2017 at 16:01

3 Answers 3

1

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()
    }
Sign up to request clarification or add additional context in comments.

4 Comments

woow! very close to what I want. Thanks @svetoslav. I'll play with this to my desired uiimage
Yes i know that it is not exactly the same ,but i think it will be easy for you to manage with it now. If you have question i am here to answer
Hi svetoslav. How to make the edges of the red rectangle rounded?
thanks. It is working! but is it possible to only roundup one of the edges? and not both?
1

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

1 Comment

Thanks for this alternative. Sorry I cant upvote ur answer not enough reputation
0

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.

1 Comment

sorry bro. noob on core graphics here. I dont understand this =/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.