I'm working on a sort of drawing app using objective-c, and for one of my UIViews, I want there to be a background image to it. However, I want this background image on the actual UIView, not a separate UIImageView. I did that using this:
self.tempDrawImage.image = [UIImage imageNamed:#"image.jpg"];
In this code, tempDrawImage is a UIImageView I made programmatically, and after initializing it, I wrote this later in the code so that the drawings would appear on top of the image. I don't know if this is helpful, but I thought I'd include it anyway just in case it does help.
- (UIImageView *)tempDrawImage
{
if(!_tempDrawImage) _tempDrawImage = [UIImageView new];
return _tempDrawImage;
}
- (void)drawRect:(CGRect)rect
{
UIGraphicsGetCurrentContext();
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
Now, I'm struggling to make the image that I set to image.jpg in the beginning aspect fit. How could I do that?
Try this
self.tempDrawImage.contentMode = UIViewContentModeScaleAspectFit;
You can use UIViewContentModeScaleAspectFit
self.tempDrawImage.contentMode = UIViewContentModeScaleAspectFit;
Related
My app sends a GET request to google to attain certain user information. One piece of crucial returned data is a users picture which is placed inside a UIImageView that is always exactly (100, 100) then redrawn to create a round mask for this imageView. These pictures come from different sources and thus always have different aspect ratios. Some have a smaller width compared to their height, sometimes it's vice-versa. This results in the image looking compressed. I've tried things such as the following (none of them worked):
_personImage.layer.masksToBounds = YES;
_personImage.layer.borderWidth = 0;
_personImage.contentMode = UIViewContentModeScaleAspectFit;
_personImage.clipsToBounds = YES;
Here is the code I use to redraw my images (it was attained from user fnc12 as the third answer in Making a UIImage to a circle form):
/** Returns a redrawn image that had a circular mask created for the inputted image. */
-(UIImage *)roundedRectImageFromImage:(UIImage *)image size:(CGSize)imageSize withCornerRadius:(float)cornerRadius
{
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0); //<== Notice 0.0 as third scale parameter. It is important because default draw scale ≠ 1.0. Try 1.0 - it will draw an ugly image...
CGRect bounds = (CGRect){CGPointZero, imageSize};
[[UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:cornerRadius] addClip];
[image drawInRect:bounds];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return finalImage;
}
This method is always called like so:
[_personImage setImage:[self roundedRectImageFromImage:image size:CGSizeMake(_personImage.frame.size.width, _personImage.frame.size.height) withCornerRadius:_personImage.frame.size.width/2]];
So I end up having a perfectly round image but the image it self isn't right aspect-wise. Please help.
P.S. Here's how images look when their width is roughly 70% that of their height before the redrawing of the image to create a round mask:
Hello dear friend there!
Here is my version that works:
Code in ViewController:
[self.profilePhotoImageView setContentMode:UIViewContentModeCenter];
[self.profilePhotoImageView setContentMode:UIViewContentModeScaleAspectFill];
[CALayer roundView:self.profilePhotoImageView];
roundView function in My CALayer+Additions class:
+(void)roundView:(UIView*)view{
CALayer *viewLayer = view.layer;
[viewLayer setCornerRadius:view.frame.size.width/2];
[viewLayer setBorderWidth:0];
[viewLayer setMasksToBounds:YES];
}
May be you should try to change your way to create rounded ImageView using my version that create rounded ImageView by modifying ImageView's view layer . Hope it helps.
To maintain aspect ratio of UIImageView, after setting image use following line of code.
[_personImage setContentMode:UIViewContentModeScaleAspectFill];
For detailed description follow reference link:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImageView_Class/
So I've been playing around with the iOS 8 beta and implementing the new UIEffectViews in the places that my app needed them. Now I've run into the issue that I still want to have backwards compatibility for iOS 7, but maintain the vibrancy effect because it really helps readability. I've used UIToolbars in the past for a blur effect, and they work great, but not for vibrancy. I thought I'd subclass UIView and add a toolbar subview and then do some clever rendering to sort of achieve the vibrancy effect which would look like this:
1. render the toolbar to a UIImage
2. render the vibrant content to a UIImage
3. mask the toolbar image to the vibrant content image mask
4. mess with the saturation and brightness
5. have a subview of the UIView display the final result over the toolbar
I've tried doing this in drawRect: of the UIView but it doesn't want to redraw every frame, and setting a timer really messes with animation, even though the render time isn't very high. If anyone can point me to sample code or a open source library, it would be much appreciated.
Thanks.
So I never posted an answer, but I did figure it out.
The brute force approach I tried was to use Core Image effects. I would render the superview to a UIImage, blur it, then overlay it on a toolbar with the dark style. This looked great, but even on a GPU context on my 5S, it was pretty slow, so theres no way it would work on other devices. This is the best I could get it to look, and would work great for static content, but is not practical for real-time.
I was able to achieve a real time version, but it doesn't look quite as good. Basically what I do is render all the vibrant content to a image and use it for a mask for a view. Then I make the view barely visible (like .2 alpha), and then put it over a toolbar. It doesn't look quite as vibrant as iOS8, or the original CI version, but it works great and preforms well.
Heres a bit of code you can just copy and paste if you really want:
-(instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor colorWithWhite:1 alpha:0.2];
maskingContents = [[UIView alloc] initWithFrame:self.bounds];
[self addSubview:maskingContents];
}
return self;
}
-(void)addSubview:(UIView *)view
{
if (![view isEqual:maskingContents])
{
[maskingContents setHidden:NO];
[maskingContents addSubview:view];
//now we need to mask it
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);
[maskingContents.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage* mask = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//apply the mask
CALayer* maskLayer = [CALayer layer];
maskLayer.frame = self.bounds;
[maskLayer setContents:(id)mask.CGImage];
[self.layer setMask:maskLayer];
[maskingContents setHidden:YES];
} else [super addSubview:view];
}
-(void)forceVibrancyUpdate
{
[maskingContents setHidden:NO];
//now we need to mask it
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);
[maskingContents.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage* mask = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//apply the mask
CALayer* maskLayer = [CALayer layer];
maskLayer.frame = self.bounds;
[maskLayer setContents:(id)mask.CGImage];
[self.layer setMask:maskLayer];
[maskingContents setHidden:YES];
}
#end
If you want to dynamically update the content inside the vibrancy view, you would call forceVibrancyUpdate, as that would re-render the mask and apply it. Hope this helped everyone.
What I'm doing is creating filling in a view's background with an image returned from a UIImagePickerController. The image fills fine in portrait mode; however, the image will repeat when filled as background in landscape mode, but I have no idea why this is occuring. This is a private method I use to resize my image.
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize landscape:(BOOL)landscape {
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
When this method is called the newsize parameter is equal to the views bounds size (self.view.bounds.size). The size is accessed after the view's transformation to landscape, but the image doesn't properly.
This is the code that is called right after getting an image from the UIImagePickerController.
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
if (image.size.width > image.size.height) {
self.view.transform = CGAffineTransformRotate(self.view.transform, M_PI_2);
self.composition.landscapemode = YES;
} else {
self.composition.landscapemode = NO;
}
self.composition.image = [NewCompositionViewController imageWithImage:image scaledToSize:self.view.bounds.size landscape:self.composition.landscapemode];
self.view.backgroundColor = [UIColor colorWithPatternImage:self.composition.image];
[self dismissViewControllerAnimated:YES completion:nil];
}
[UIColor colorWithPatternImage:] is meant for tiling images, so it's behaving as it should.
I would recommend creating a UIImageView with screen-sized frame, setting an image to it, and adding it as subview:
UIImageView *backgroundImage = [[UIImageView alloc] initWithFrame:self.view.frame];
[backgroundImage setImage:self.composition.image];
// choose best mode that works for you
[backgroundImage setContentMode:UIViewContentModeScaleAspectFill];
[self.view insertSubview:backgroundImage atIndex:0];
//OR
[self.view addSubview:backgroundImage];
[self.view sendSubviewToBack:backgroundImage];
once it's added, you can rotate it and experiment with autoresizing masks to make sure it's displayed properly for all orientations. Exact method would depend on if you are using auto-layout or not.
UIViewContentModeScaleAspectFill may be more appropriate here than UIViewContentModeScaleAspectFit since the image is filling a background view. AspectFit will maintain the image's aspect ratio and make the entire image fit in the space, which may leave portions of the view transparent. AspectFill also maintains aspect ratio, but will fill the entire view and clip any portions of the image that don't match the view bounds.
I've been able to apply an "aspect fit" UIImage to a UIView background by combining a few AVFoundation and UIKit APIs. Here's one example:
UIImage *image = [UIImage imageWithContentsOfFile:self.desiredBackgroundImageFilePathString];
UIGraphicsBeginImageContext(self.drawingImage.frame.size);
[image drawInRect:AVMakeRectWithAspectRatioInsideRect(image.size, self.drawingImage.bounds)];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.drawingImage.backgroundColor = [UIColor colorWithPatternImage:image];
This flows through a few simple, but important steps:
Generate a UIImage from a file (or whatever).
Define the context of the image (the desired UIView for the background) with UIGraphicsBeginImageContext().
Use drawInRect in combination with AVMakeRectWithAspectRatioInsideRect to scale the image. Provide AVMakeRect...() with the image's .size and the bounds of the target UIView.
Apply the resized image to the desired image context.
Apply your now-resized image to the .backgroundColor of the target UIView using colorWithPatternImage.
I'm able to swap out images with both landscape and portrait aspect ratios without alignment or clipping issues using this code.
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).
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.