add UIImage in CALayer
This is a general answer for the sake of future viewers. It is based on the question title rather than the details of the original question.
How to add a UIImage to a CALayer
You can add an image to a view's layer
simply by using its contents
property:
myView.layer.contents = UIImage(named: "star")?.cgImage
- Note that the
UIImage
needs to be converted to aCGImage
.
If you wish to add the image in its own layer, you can do it like this:
let myLayer = CALayer()
let myImage = UIImage(named: "star")?.cgImage
myLayer.frame = myView.bounds
myLayer.contents = myImage
myView.layer.addSublayer(myLayer)
Modifying the appearance
The above code produces a view like this. The light blue is the UIView
and the dark blue star is the UIImage
.
As you can see, though, it looks pixelated. This is because the UIImage
is smaller than the UIView
so it is being scaled to fill the view, which is the default it you don't specify anything else.
The examples below show variations on the layer's contentsGravity
property. The code looks like this:
myView.layer.contents = UIImage(named: "star")?.cgImage
myView.layer.contentsGravity = kCAGravityTop
myView.layer.isGeometryFlipped = true
In iOS, you may want to set the isGeometryFlipped
property to true
if you are doing anything with top or bottom gravity, otherwise it will be the opposite of what you expect. (Only the gravity is flipped vertically, not the content rendering. If you are having trouble with the content being flipped, see this answer.)
There are two UIView
examples below for every contentsGravity
setting, one view is larger than the UIImage
and the other is smaller. This way you can see the effects of the scaling and gravity.
kCAGravityResize
This is the default.
kCAGravityResizeAspect
kCAGravityResizeAspectFill
kCAGravityCenter
kCAGravityTop
kCAGravityBottom
kCAGravityLeft
kCAGravityRight
kCAGravityTopLeft
kCAGravityTopRight
kCAGravityBottomLeft
kCAGravityBottomRight
Related
- Content mode property of a view
- Drawing a
UIImage
indrawRect
withCGContextDrawImage
- CALayer Tutorial: Getting Started
UIImage from CALayer in iOS
Sounds like you want to render your layer into a UIImage. In that case, the method below should do the trick. Just add this to your view or controller class, or create a category on CALayer.
Obj-C
- (UIImage *)imageFromLayer:(CALayer *)layer
{
UIGraphicsBeginImageContextWithOptions(layer.frame.size, NO, 0);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage;
}
Swift
func imageFromLayer(layer:CALayer) -> UIImage {
UIGraphicsBeginImageContextWithOptions(layer.frame.size, layer.isOpaque, 0)
layer.render(in: UIGraphicsGetCurrentContext()!)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage!
}
CAlayer to UIImage bug with shadow
after searching and testing, it turned out that the problem is in the shadowPath, and you can render it only through UIView and drawhierarchy https://developer.apple.com/documentation/uikit/uiview/1622589-drawhierarchy
extension UIImage{
convenience init(view: UIView) {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.init(cgImage: (image?.cgImage)!)
}
}
Swift Get UIImage from layers of UIView
If the size passed to UIGraphicsBeginImageContext(_)
is zero in either or both dimension(s) then UIGraphicsGetCurrentContext()
returns nil
and so will UIGraphicsGetImageFromCurrentImageContext()
.
UIImageView + UIImage vs CALayer + Content Efficiency
In general, UIView
objects are fairly thin wrappers around CALayers
. UIImageView
is no exception to that. Most of the "heavy lifting" of decoding and displaying the image is done by the CALayer
in both cases, so I doubt if you'll see much difference.
UIImageView
is easier to use, and the resulting code is easier to read, so unless you need to do something that requires you to use CALayers
, I'd stick with UIKit
objects.
How to add Stretchable UIImage in the CALayer.contents?
The response to this question is this one. Lets say you have a stretchable image which stretches only in width and has the height fixed (for simplicity sake).
The image is 31px width ( 15px fixed size - doesn't stretch -, 1px will be stretched)
Assuming your layer is a CALayer subclass your init method should look like this:
- (id)init
{
self = [super init];
if (self) {
UIImage *stretchableImage = (id)[UIImage imageNamed:@"stretchableImage.png"];
self.contents = (id)stretchableImage.CGImage;
self.contentsScale = [UIScreen mainScreen].scale; //<-needed for the retina display, otherwise our image will not be scaled properly
self.contentsCenter = CGRectMake(15.0/stretchableImage.size.width,0.0/stretchableImage.size.height,1.0/stretchableImage.size.width,0.0/stretchableImage.size.height);
}
return self;
}
as per documentation the contentsCenter rectangle must have values between 0-1.
Defaults to the unit rectangle (0.0,0.0) (1.0,1.0) resulting in the entire image being scaled. If the rectangle extends outside the unit rectangle the result is undefined.
This is it. Hopefully someone else will find this useful and it will save some development time.
Related Topics
Uploading Image with Afnetworking 2.0
Swift Equivalent to '[Nsdictionary Initwithobjects: Forkeys:]'
Swift Programmatically Navigate to Another View Controller/Scene
How to Add Minutes to Current Time in Swift
How to Make a Background Image Scale to Screen Size in Swift
iOS - Calling App Delegate Method from Viewcontroller
Uicollectionview Reloaddata Not Functioning Properly in iOS 7
Ios: Copy a File in Documents Folder
Custom Annotation View for Userlocation Not Moving the Mapview
Swiftui - Multiple Buttons in a List Row
How to Rotate Text for Uibutton and Uilabel in Objective-C
Foreign Key Relationship Mapping with Restkit
iOS 8 - Can't Install Enterprise App
Navigation Bar Rightbaritem Image-Button Bug iOS 11
Ios9 Does Not Load Insecure Resources from a Secure Page (Ssl/Https)
Add Bottom Border Line to UI Textfield View in Swiftui/Swift/Objective-C/Xamarin
With Auto Layout, How to Make a Uiimageview's Size Dynamic Depending on the Image