In iPhone or iPad applications we sometimes need to display images or photos with borders and shadows around them. There are few ways to achieve this but generally I tend to use UIImageView. There are few reasons why I prefer this solution. First according to iOS documentation, UIImageView is optimized to display images. Second it is less lines of code. I will discuss how we can convert image as shown in figure 1 to image with border and shadow in figure 2. Once you understand the basic concept of drawing borders and shadows I would invite you to read my next post: UIImageView curl shadow effect using shadowPath. This post discusses how to render shadows efficiently.
First we extend UIImageView interface with some functions. We create an objective-c class using XCode File new wizard. We name our files UIImageViewBorder.h and UIImageViewBorder.m. In UIImageViewBorder.h file we define our interface as shown below:
To solve this problem we scale down the original image according to the area which is available after drawing the border. We define a function rescaleImage which scales the image according to available image area.
We define public function setImage which calls configureImageViewBorder and rescaleImage to draw border and image scaling.
We are now ready to use this function. We can use this on UIImageView as follows:
Note:
I have noticed that the border of UIImageView does not update properly if autoresizingMask property of UIImageView is set to either UIViewAutoresizingFlexibleWidth or UIViewAutoresizingFlexibleHeight or both. In above examples I am using default value which is UIViewAutoresizingNone. Please feel free to contribute if you know how to fix this problem. Thanks.
Figure1: image without border. |
Figure 2: image with white border and a shadow. |
First we extend UIImageView interface with some functions. We create an objective-c class using XCode File new wizard. We name our files UIImageViewBorder.h and UIImageViewBorder.m. In UIImageViewBorder.h file we define our interface as shown below:
#import <Foundation/Foundation.h > @interface UIImageView (ImageViewBorder) -(void)setImage:(UIImage*)image withBorderWidth:(CGFloat)borderWidth; @endIn this interface we define one function which receives original image such as image in figure 1 with some border width. Now we define the implementation of this class in UIImageViewBorder.m file.
#import "UIImageViewBorder.h" #import "QuartzCore/QuartzCore.h" @implementation UIImageView (ImageViewBorder) @endFirst we will define a function to create a border around an image view. This step is simple as shown in code below:
-(void)configureImageViewBorder:(CGFloat)borderWidth{ CALayer* layer = [self layer]; [layer setBorderWidth:borderWidth]; [self setContentMode:UIViewContentModeCenter]; [layer setBorderColor:[UIColor whiteColor].CGColor]; [layer setShadowOffset:CGSizeMake(-3.0, 3.0)]; [layer setShadowRadius:3.0]; [layer setShadowOpacity:1.0]; }In this function we get the layer object contained by UIImageView. We then set the border width and set the content mode to center. We define the border color to white and set the shadow offset to (-3.0, 3.0). The shadow radius is 3.0 and opacity is 1.0. Please note that these values can be changed as needed. Now with this function we can set the border around UIImageView. However we will find a slight problem with this. For example if UIImageView size is (100, 100) and image size is also (100,100). If we draw a border of width say 10.0 around UIImageView then some part of the image will be hidden by the border as shown in figure 3.
Figure 3: Part of image hidden by border with width 10.0 |
-(UIImage*)rescaleImage:(UIImage*)image{ UIImage* scaledImage = image; CALayer* layer = self.layer; CGFloat borderWidth = layer.borderWidth; //if border is defined if (borderWidth > 0) { //rectangle in which we want to draw the image. CGRect imageRect = CGRectMake(0.0, 0.0, self.bounds.size.width - 2 * borderWidth,self.bounds.size.height - 2 * borderWidth); //Only draw image if its size is bigger than the image rect size. if (image.size.width > imageRect.size.width || image.size.height > imageRect.size.height) { UIGraphicsBeginImageContext(imageRect.size); [image drawInRect:imageRect]; scaledImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); } } return scaledImage; }In this function we first get the border width of UIImageView. We only want to scale down the image if border width is defined for UIImageView. We calculate the available image area inside UIImageView. If image is already scaled down or less than the size of available image area then we do not perform this operation as image can fit in the area without processing. If image is bigger than the available image then we define an image graphics context with the size of available image area. We then draw original image into this area.
We define public function setImage which calls configureImageViewBorder and rescaleImage to draw border and image scaling.
-(void)setImage:(UIImage*)image withBorderWidth:(CGFloat)borderWidth { [self configureImageViewBorder:borderWidth]; UIImage* scaledImage = [self rescaleImage:image]; self.image = scaledImage; }configureImageViewBorder and rescaleImage functions are internal functions so we make them private by defining interface in UIImageViewBorder.m file as follows:
@interface UIImageView (private) -(UIImage*)rescaleImage:(UIImage*)image; -(void)configureImageViewBorder:(CGFloat)borderWidth; @end
We are now ready to use this function. We can use this on UIImageView as follows:
UIImage* image = [UIImage imageNamed:@"dog"]; [imageView setImage:image withBorderWidth:10.0];In the above code we are assuming that the UIImageView is already created.
Note:
I have noticed that the border of UIImageView does not update properly if autoresizingMask property of UIImageView is set to either UIViewAutoresizingFlexibleWidth or UIViewAutoresizingFlexibleHeight or both. In above examples I am using default value which is UIViewAutoresizingNone. Please feel free to contribute if you know how to fix this problem. Thanks.
Congratulations on a well-designed website and blog, and on superb presentations.
ReplyDeleteI'm trying this on iOS 6 and while I can get the border to draw the image does not display. I get no error. I used storyboard to add the UIImageView and command-click to create an IBOutlet. I've even gone back and literally copy pasted every line you have above incase I typed something in wrong.
ReplyDeleteCould it be something with iOS 6?
UIImageViwBorder.h: http://pastebin.com/QH84wRyu
UIImageViwBorder.m: http://pastebin.com/qHJJS1Ju
ViewController.h: http://pastebin.com/Fu4heWDh
ViewController.m: http://pastebin.com/Fu4heWDh
Screenshot: http://imagr.eu/up/509829e327b482_iOS_Simulator_Screen_shot_Nov_5,_2012_4.04.23_PM.png
Any help would be greatly appreciated.
Great tutorial, exactly what i was looking for. Thanks!
ReplyDeleteStill working on 2017 versions (IOS10+,code8+), This is great, thank you, really helpful.
ReplyDelete