UIImageView stretch/repeat image on borders and maintain its quality - ios

I have a squared UIImage
I'm trying to create a UIImageView using this UIImage for any given rect which I'll be using as a border to another view on top of it.
I don't want to set the border of the layer manually but I would like to use this image.
Example of desired output:
I tried using UIView's UIViewContentModeScaleToFill
UIImageView *imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 300, 150)];
[imageView setImage:[UIImage imageNamed:#"background"]];
[imageView setContentMode:UIViewContentModeScaleToFill];
But the image is stretching and not returning the desired output
Example output:

Programmatically you can create border with shadow effect:
[view.layer setCornerRadius:5];
[view.layer setShadowColor:[UIColor lightGrayColor].CGColor];
[view.layer setShadowOpacity:0.4];
[view.layer setShadowRadius:1.0];
[view.layer setShadowOffset:CGSizeMake(1.0, 1.0)];
Although if you want to do it using Xcode interface, you can do it as
Drag & drop your square image into Assets
Select image & click on "Show the Attribute Inspector"
In Slicing section select "Horizontal and Vertical" for Slices
Now Use it as you want you will have stretch image without any distortion
You can view image slice view on clicking "Show Slicing" at the bottom
You can also do it programatically using
resizableImageWithCapInsets:resizingMode:

Related

Apply circular crop to UIImage or UIImageView

How can I programmatically apply a circular crop out to a UIImage or a UIImageView? Is it possible, or must I use a graphical mask?
Till now I am using a graphical mask (a png image) but the final crop out result is ovalized, rather than a perfect circle.
[imageView setContentMode: UIViewContentModeScaleAspectFit];
[imageView setContentMode: UIViewContentModeScaleAspectFill];
also do not solve the problem.
Please note that the UIImageView that the image is applied to is already defined exactly as a square in IB.
If the UIImageView is already a square then you can set the corner radius of its layer to half of its width/height
[imageView.layer setCornerRadius:imageView.frame.size.width / 2.0];
[imageView.layer setMasksToBounds:YES];

IOS Button border thickness lssue,why?

UIButton top border appears thicker than the following ,but sometimes correct ,why?
code:
UIImage * sanImage = [UIimage imageNamed:#"product_bt1_normal"];
[self.saveBtn setBackgroundImage:[sanImage
stretchableImageWithLeftCapWidth:sanImage.size.width/3
topCapHeight:sanImage.size.height/3] forState:UIControlStateNormal];
Are you trying to make a button? If so, perhaps use a UIButton instead? You can control the border with button.layer.borderWidth = 1.0f
If you're set on using an image, create a UIImageView, and modify the border thickness that way:
UIImageView *iv = [[UIImageView alloc] initWithImage:sanImage];
[iv.layer setBorderWidth:0.5f];
It could be because of off-pixel boundaries. Since you are using height/3.0f, your image is maybe not returning a well-behaved image.
Also, there is a new stretchable image method you should be using, resizableImageWithCapInsets:.
So try this code out:
[self.saveBtn setBackgroundImage:[sanImage resizableImageWithCapInsets:UIEdgeInsetsMake(3.0f, 3.0f, 3.0f, 3.0f)] forState:UIControlStateNormal];
You might need to mess with the values for the insets a bit, I don't know the dimensions of your button image.

How to set the imageView property in a UITableCellView to show only a background color?

I have a custom class inheriting from UITableViewCell class that shows either an image (left to the title) or a generic dark-colored square if the image is not available). The following code shows a dark square on a light-colored cell background:
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(11, 6, 40, 40)];
[imageView setBackgroundColor:kBackgroundGreyColour];
[cell.contentView addSubview:imageView];
However, instead of creating a custom subview in each table cell I would rather like to use the existing imageView property of the generic UITableViewCell class and modify it somehow to show the square as the code above does. This is what I am trying at this moment:
UIImageView* iv = [[UIImageView alloc] initWithFrame:CGRectMake(11, 6, 40, 40)];
[iv setBackgroundColor:[UIColor redColor]];
self.imageView.hidden = NO;
self.imageView.opaque = iv.opaque;
self.imageView.alpha = iv.alpha;
self.imageView.image = iv.image;
[self bringSubviewToFront:self.imageView];
[self.imageView setBackgroundColor:[UIColor redColor]];
I added all those lines to set as many of the existing UIImageView properties to the same values as the created UIImageView instance in the first code snippet, and yet the second code snippet doesn't show any dark square. It just doesn't show anything at all and the cell looks like there is just the light background and no image view visible. But I see that the imageView property is not nil so executing all those lines of code in the second snippet should show something?
However, as soon as I assign a new image to the imageView property (e.g. self.imageView.image = [[UIImage alloc] init...], the square shows the assigned image without problems.
Edit: Just a note that in the second case I am setting the frame of the imageView in layoutSubview function, e.g.:
-(void)layoutSubviews
{
[super layoutSubviews];
self.imageView.frame = CGRectMake(11, 6, 40, 40);
}
So my questions are:
1. Which properties of the existing imageView property I would need to set and to what values so that the code will show a square filled with a specific color (like the first snippet of code does)?
Is there a way of creating the UIImage programatically so that it shows only a background color without any image associated with it (and which I could use to set the imageView.image property to show that color).
Is it possible to replace the existing imageView property in a UITableViewCell class with a custom view without adding a custom subview (like the first code snippet did), so that I can show a placeholder UIView with a background color when the image is not available?
The reason why your code doesn't work, is as you guessed; Because when you set the background colour of an imageview, it doesn't create anything on the image property.
And, you've figured out that you can't directly set the imageview property of the cell either.
I'd say your best bet, is the former option; To create a UIImage programmatically.
Although, I'd highly suggest simply creating one in your favourite image editing software then including it in the bundle. It makes for easy replacement later, for when you may get a better image, and next to no code and effort required to replace.
But if you still wish to do it all programmatically, it's not as simple as you'd hope.
CGRect rect = CGRectMake(11, 6, 40, 40);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [kBackgroundGreyColour CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageview.image = image;
Should do the trick.
This defines the image size, creates a graphics context (think of it as a canvas), picks your grey colour to use, paints the canvas with it, then scans it into your computer into the small little size you wanted.
The little green imp does it all behind the screen (Sorry, too much Terry Pratchett).

Center [UIColor colorWithPatternImage]?

I couldn't find anything on how you can center the 'image' when you use (maybe you can't):
[self setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"background"]]];
Setting my [self setContentMode:UIContentModeCenter]; doesnt help.
Do I have to manually draw the image (either in drawRect or set the content of the CALayer? Which one if preferable?
I think you're on the wrong path here: you create a UIColor from a pattern (pattern already implies this is a repeating image). All in all- you can't have your pattern not repeat and centered.
If you just want simple image as background of your UIView, just add it as a subview and center it.
UIImage* img = [UIImage imageNamed:#"yourfile.png"];
UIImageView* imgView = [[UIImageView alloc]initWithImage: img];
[yourUIView addSubview: imgView];
imgView.center = CGPointMake(yourUIView.frame.size.width/2, yourUIView.frame.size.height/2);
Now - add more subviews to your "yourUIView" view and they'll show on top of the image - thus the image becoming the background.
So... no need to draw anything yourself.

iOS - can stretch a UIImageView but not a UIButton?

Behold:
//UIImageView* stretchTest = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image.png"]];
//[self addSubview:stretchTest];
UIButton *stretchTest = [UIButton buttonWithType:UIButtonTypeCustom];
[stretchTest setFrame:CGRectMake(0, 0, 400, 100)];
[stretchTest setBackgroundImage:[UIImage imageNamed:#"image.png"] forState:UIControlStateNormal];
[self addSubview:stretchTest];
stretchTest.contentStretch = CGRectMake(0.5, 0.5, 0, 0);
stretchTest.contentMode = UIViewContentModeScaleToFill;
CGRect frame = stretchTest.frame;
frame.size.height = 300;
stretchTest.frame = frame;
Using the UIImageView (commented out above), the image stretches appropriately - rounded corners maintain the correct radius, because only the center pixel of the image gets stretched.
Using the UIButton, the image gets stretched incorrectly. The corner radii are not maintained and it gets ugly.
Both UIImageView and UIButton are subclasses of UIView. Why does the button resize differently than the imageView?
You're making assumptions about the way UIButton works. It's not implemented the same way as UIImageView. UIImageView is just a view, with no subviews, and its contents is the image. UIButton is different, and the way it works is a private implementation detail.
If you're trying to stretch an image appropriately on a button, you should use -[UIImage stretchableImageWithLeftCapWidth:topCapHeight:] to get a UIImage that knows how it should be stretched. If you want to stretch just the middle pixel, you can use something like
UIImage *image = [UIImage imageNamed:#"image.png"];
image = [image stretchableImageWithLeftCapWidth:floorf(image.size.width/2) topCapHeight:floorf(image.size.height/2)];
A UIButton has two types of images it can display -- a foreground image and a background image. The background image for a button is expected to replace the button's background texture. As such, it will stretch to fill the entire background. The button's foreground image is expected to be an icon that may or may not display alongside text; it will not stretch. It may shrink if the frame is smaller than the image, but it will not stretch.
A button's foreground and background image can be set in code like this:
// stretchy
[self setBackgroundImage:backgroundImage forState:UIControlStateNormal];
// not stretchy
[self setImage:forgroundImage forState:UIControlStateNormal];
By default, the backgroundImage of a button will use scaleToFill to stretch the image. If you need the image to stretch using cap insets though, you should set them on the image before assigning it to the backgroundImage, like this:
UIImage *image = [UIImage imageNamed:#"bg_image.png"];
/* This assumes your image will have a 1px column and 1px row of pixels
in the horizontal and vertical middle of the image that should be
stretchable. If that's not the case (such as asymetrical buttons)
you need to adjust the caps */
image = [image stretchableImageWithLeftCapWidth:floorf(image.size.width/2)
topCapHeight:floorf(image.size.height/2)];
[self setBackgroundImage:image forState:UIControlStateNormal];

Resources