UIImageView: combine UIViewContentModeScaleAspectFit and UIViewContentModeBottom - iphone

Is there a way to avoid image stretching in an UIImageView and aligning it to the bottom at the same time? Basically I want to obtain what would happen if it was possible to combine the UIViewContentModeScaleAspectFit and UIViewContentModeBottom contentModes.

Found the solution on my own. This code resizes the UIImageView to its image's size, and moves it at the bottom of its superview.
CGSize initialImageSize = imageView.size;
CGSize imageSize = imageView.image.size;
CGFloat aspectRatio = imageSize.width / imageSize.height;
CGRect imageFrame = imageView.frame;
if (initialImageSize.width / aspectRatio <= initialImageSize.height) {
imageFrame.size.width = initialImageSize.width;
imageFrame.size.height = imageFrame.size.width / aspectRatio;
} else {
imageFrame.size.height = initialImageSize.height;
imageFrame.size.width = imageFrame.size.height * aspectRatio;
}
CGRect parentFrame = imageView.superview.frame;
imageFrame.origin.y = (parentFrame.origin.y + parentFrame.size.height) - imageFrame.size.height;
imageView.frame = imageFrame;

Constraint based approach
You'll want to constrain the left, right, and bottom sides of the UIImageView while ensuring the ratio of the size is the same as the UIImage that it's displaying.
UIImage *image; // allocate image object here
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[parent addSubview:imageView]; // add imageView to proper view with addSubview: here
UIView *superview = imageView.superview; // match width and bottom of self.superview
CGFloat ratio = image.size.width / image.size.height;
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeft multiplier:1.f constant:0.f];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeRight multiplier:1.f constant:0.f];
NSLayoutConstraint *ratioConstraint = [NSLayoutConstraint constraintWithItem:imageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:imageView
attribute:NSLayoutAttributeHeight
multiplier:ratio
constant:1.f];
[imageView addConstraint:ratioConstraint];
[superview addConstraints:#[leftConstraint, bottomConstraint, rightConstraint]];
This will emulate a combination of UIViewContentModeScaleAspectFit and UIViewContentModeBottom but will resize the height of the UIImageView as well.

My solution:
float newwidth;
float newheight;
if (image.size.height>=image.size.width){
newheight=imageview.frame.size.height;
newwidth=(image.size.width/image.size.height)*newheight;
if(newwidth>imageview.frame.size.width){
float diff=imageview.frame.size.width-newwidth;
newheight=newheight+diff/newheight*newheight;
newwidth=imageview.frame.size.width;
}
}
else{
newwidth=imageview.frame.size.width;
newheight=(image.size.height/image.size.width)*newwidth;
if(newheight>imageview.frame.size.height){
float diff=imageview.frame.size.height-newheight;
newwidth=newwidth+diff/newwidth*newwidth;
newheight=imageview.frame.size.height;
}
}

I have found a much easier way to do it.
imageView.contentMode = .Bottom
imageView.clipToBounds = true
This will prevent the image from resizing no matter what frame it is bounded in. And the clipToBounds part is important because it prevents the non resized image from going outside the imageView bounds.

Late to the party, but a simple solution. On the UIImageView:
Use the contentMode property to position the image. (in the current case UIView.ContentMode.bottom)
Use the contentScaleFactor property of the UIImageView to scale the image in the content view.
This will maintain the aspect ratio, just calculate the scale you need. For scaleAspectFit:
yourImageView.contentMode = UIView.ContentMode.bottom
let relWidthScale = yourImage.size.width/yourImageView.frame.width
let relHeightScale = yourImage.size.height/yourImageView.frame.height
yourImageView.contentScaleFactor = min(relWidthScale,relHeightScale)
If the UIImageView changes size, you can update the scale by adding an observer to the bounds property of the UIImageView or its container.

Related

crop a zoomed image in ImageView inside scrollView

I already do Lot of efforts from my Side. finally I need help. thanks
Goal :
1) How I fit imageView inside ScrollView
2) How I crop a zoomed Image in inside scrollView.
I have a imageView inside Scroll View. I wants crop image after zoomed which is display inside scrollview boundary. I cropped image already but it not exactly same which i wants.
Here I set backgroundColor Black to my scrollView. And when I place imageView inside it, it's not fit.
after zoom image inside scroll view is
and after crop image is
and my code is here :
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect frame1 = CGRectMake(50,50,200,200);
CGRect frame2 = CGRectMake(50,50,200,200);
imageView1=[[UIImageView alloc]initWithFrame:frame1];
imageView1.image= [UIImage imageNamed:#"back.jpeg"];
imageView1.backgroundColor=[UIColor brownColor];
imageView1.contentMode = UIViewContentModeScaleAspectFit;
scroll=[[UIScrollView alloc]initWithFrame:frame2];
scroll.backgroundColor=[UIColor blackColor];
[scroll addSubview:imageView1];
scroll.delegate=self;
[self.view addSubview:scroll];
[self setContentSizeForScrollView];
self.imageView1.userInteractionEnabled = YES;
}
setting scroll view contentSize
-(void)setContentSizeForScrollView
{
// scroll.contentSize = CGSizeMake(imageView1.frame.size.width,imageView1.frame.size.height);
scroll.contentSize = CGSizeMake(200, 200);
scroll.minimumZoomScale = .50;
scroll.maximumZoomScale = 1.5;
}
and my crop logic is
-(IBAction)cropButtonClicked
{
//Calculate the required area from the scrollview
CGRect rect = CGRectMake(50, 50, 200,200);
UIImage *image = [self imageByCropping:imageView1.image toRect:rect];
imageView1.image=image;
imageView1.contentMode = UIViewContentModeScaleAspectFit;
}
And this method crop image :
- (UIImage*)imageByCropping:(UIImage *)myImage toRect:(CGRect)cropToArea{
CGImageRef cropImageRef = CGImageCreateWithImageInRect(myImage.CGImage, cropToArea);
UIImage* cropped = [UIImage imageWithCGImage:cropImageRef];
CGImageRelease(cropImageRef);
return cropped;
}
Answer of my own Question : After many efforts i found the answer of both of my questions.
and it work good for me. I share here, may be it help someone. :)
1) Fit image View inside Scroll View. I use this link
- (void)centerScrollViewContents {
CGSize boundsSize = scroll.bounds.size;
CGRect contentsFrame = self.imageView1.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
}
else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
}
else {
contentsFrame.origin.y = 0.0f;
}
self.imageView1.frame = contentsFrame;
}
2) Crop a zoomed Image in inside scrollView. I use this link
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
[scroll.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *fullScreenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageView1.contentMode = UIViewContentModeScaleAspectFill;
UIImageWriteToSavedPhotosAlbum(fullScreenshot, nil, nil, nil);
return fullScreenshot;
I had a similar problem recently, I got the solution using the relative idea ( Xa,b = Xa,c - Xb,c )
-(IBAction)crop:(id)sender{
// F = frame
// i = image
// iv = imageview
// sv = self.view
// of = offset
//Frame Image in imageView coordinates
CGRect Fi_iv = [self frameForImage:self.image inImageViewAspectFit:self.imageView];
//Frame ImageView in self.view coordinates
CGRect Fiv_sv = self.imageView.frame;
//Frame Image in self.view coordinates
CGRect Fi_sv = CGRectMake(Fi_iv.origin.x + Fiv_sv.origin.x
,Fi_iv.origin.y + Fiv_sv.origin.y,
Fi_iv.size.width, Fi_iv.size.height);
//ScrollView offset
CGPoint offset = self.scrollView.contentOffset;
//Frame Image in offset coordinates
CGRect Fi_of = CGRectMake(Fi_sv.origin.x - offset.x,
Fi_sv.origin.y - offset.y,
Fi_sv.size.width,
Fi_sv.size.height);
CGFloat scale = self.imageView.image.size.width/Fi_of.size.width;
//the crop frame in image offset coordinates
CGRect Fcrop_iof = CGRectMake((self.cropView.frame.origin.x - Fi_of.origin.x)*scale,
(self.cropView.frame.origin.y - Fi_of.origin.y)*scale,
self.cropView.frame.size.width*scale,
self.cropView.frame.size.height*scale);
UIImage *image = [self image:self.imageView.image cropRect:Fcrop_iof];
// Use this crop image...
You can crop the image using:
//Use this code to crop when you have the right frame
-(UIImage*)image:(UIImage *)image cropRect:(CGRect)frame
{
// Create a new UIImage
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, frame);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return croppedImage;
}
Since you are using the ImageView in Aspect Fit, you need to calculate the image frame inside the imageView
-(CGRect)frameForImage:(UIImage*)image inImageViewAspectFit:(UIImageView*)imageView
{
float imageRatio = image.size.width / image.size.height;
float viewRatio = imageView.frame.size.width / imageView.frame.size.height;
if(imageRatio < viewRatio)
{
float scale = imageView.frame.size.height / image.size.height;
float width = scale * image.size.width;
float topLeftX = (imageView.frame.size.width - width) * 0.5;
return CGRectMake(topLeftX, 0, width, imageView.frame.size.height);
}
else
{
float scale = imageView.frame.size.width / image.size.width;
float height = scale * image.size.height;
float topLeftY = (imageView.frame.size.height - height) * 0.5;
return CGRectMake(0, topLeftY, imageView.frame.size.width, height);
}
}
I hope this code can work for you as it worked for me.
Best,
Rafael.

adjusting the width of UIImageView proportionally when changing height

I have the following code:
UIImageView * imgView = [[UIImageView alloc] initWithImage:image];
NSLog(#"IMAGE SIZE WIDTH IS %f AND HEIGHT IS %f", imgView.frame.size.width, imgView.frame.size.height);
[imgView setUserInteractionEnabled:YES];
[imgView setContentMode:UIViewContentModeScaleAspectFit];
CGRect frame = imgView.frame;
frame.size.width = SCREEN_WIDTH_PORTRAIT;
[imgView setFrame: frame];
however, the height of this view did not change accordingly, what is wrong?
You're telling the view's content to scale, not the view itself. You will have to set both the width and the height to do that.
If you're just trying to scale with orientation changes, though, you could use the UIViewAutoresizingMask and set it like this:
imgView.autoresizingMask = UIViewAutoresizingFlexibleWidth| UIViewAutoresizingFlexibleHeight;
That will make it stretch when switching orientations automatically.
Edit:
Here's how you would change the height and maintain the ratio, and animate to the new frame:
CGRect frame = imgView.frame;
float ratio = frame.size.width/SCREEN_WIDTH_PORTRAIT;
frame.size.width = SCREEN_WIDTH_PORTRAIT;
frame.size.height *= ratio;
[UIView animateWithDuration:.25 animations:^{
[imgView setFrame: frame];
}];
The image will fit to the frame with the same height as you are only changing the width. So, depending on the aspect ratio of the image, the image may not change it's size. You could determine the aspect ratio of the UIImage and then calculate the height from that with the new width.

Horizontal UIScrollView and hundreds of thumbnail images in iOS?

I need to create a horizontal UIScrollView which to hold hundreds of thumbnail images, just like a slide of thumbnails.
For example, there will be 10 thumbnails showing in a single screen, each of them are horizontally adjacent to each other.
My problem is that I don't know how to make a horizontal UIScrollView to hold the multiple thumbnails which showing at the same time ?
A sample photo is as below. See the bottom part of the screen.
Thanks.
You can add all the thumbnails programatically to your scrollview and use the setContentSize method of UIScrollView. you have to pass 2 values in contentOffset. 1 for width and 1 for height. Please follow link to explore more on this. If you need further help please leave a comment.
Hope it helps.
Please consider Following example.
- (void)setupHorizontalScrollView
{
scrollView.delegate = self;
[self.scrollView setBackgroundColor:[UIColor blackColor]];
[scrollView setCanCancelContentTouches:NO];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView.clipsToBounds = NO;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
NSUInteger nimages = 0;
NSInteger tot=0;
CGFloat cx = 0;
for (; ; nimages++) {
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", (nimages + 1)];
UIImage *image = [UIImage imageNamed:imageName];
if (tot==15) {
break;
}
if (4==nimages) {
nimages=0;
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = 40;
rect.size.width = 40;
rect.origin.x = cx;
rect.origin.y = 0;
imageView.frame = rect;
[scrollView addSubview:imageView];
[imageView release];
cx += imageView.frame.size.width+5;
tot++;
}
self.pageControl.numberOfPages = nimages;
[scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];
}
I suggest you to look at nimbus
Check out bjhomer's HSImageSidebarView project. It lets you load a scrollview horizontally or vertically and load in the images. Super easy to implement.
First of all, at storyboard drag and drop the scroll view and make the outlet of scrollview named scrollView. Two array one is mutable and one is immutable.
#property(nonatomic,strong)IBOutlet UIScrollView *scrollView;
#property(nonatomic,strong)NSMutableArray *images;
#property(nonatomic,strong)NSArray *imagesName;
The immutable array only store the images which we want to show on the scroll view.Make sure UIscrollview delegate is defined.
In viewcontoller.m file in didload function do following code:
imagesName = [[NSArray alloc]initWithObjects:#"centipede.jpg",#"ladybug.jpg",#"potatoBug.jpg",#"wolfSpider.jpg", #"ladybug.jpg",#"potatoBug.jpg",#"centipede.jpg",#"wolfSpider.jpg",nil];
// mutable array used to show the images on scrollview dynamic becaus after one
// image when scroll other will come
images = [[NSMutableArray alloc]init];
scrollView.delegate = self;
scrollView.scrollEnabled = YES;
int scrollWidth = 120;
scrollView.contentSize = CGSizeMake(scrollWidth,80);
int xOffset = 0;
//the loop go till all images will load
for(int index=0; index < [imagesName count]; index++)
{
UIImageView *img = [[UIImageView alloc] init];
// make the imageview object because in scrollview we need image
img.frame = CGRectMake(5+xOffset, 0, 160, 110);
// the offset represent the values, used so that topleft for each image will
// change with(5+xOffset, 0)and the bottomright(160, 110)
NSLog(#"image: %#",[imagesName objectAtIndex:index]);
img.image = [UIImage imageNamed:[imagesName objectAtIndex:index]];
// The image will put on the img object
[images insertObject:img atIndex:index];
// Put the img object at the images array which is mutable array
scrollView.contentSize = CGSizeMake(scrollWidth+xOffset,110);
//scroll view size show after 125 width the scroll view enabled
[scrollView addSubview:[images objectAtIndex:index]];
// set images on scroll view
xOffset += 170;
}
You can calculate content size width of the scrollview as width = number of images * size of each image. Then set contentSize of the scrollview to this width and the height that you want (scrollView.contentSize = CGSizeMake(width, height))

UIScrollView height change

I have a UITableView containing a list of maps. When an item is selected a new sub view is added to the main window and the map is shown. In my view controller for the map view the following method gets called each time it's displayed:
- (void)showMap {
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:mapImage]];
float imageHeight = tempImageView.image.size.height;
float targetHeight = scrollView.frame.size.height - mapNavigationController.navigationBar.frame.size.height;
scrollView.contentSize = tempImageView.image.size;
scrollView.maximumZoomScale = 1.0;
scrollView.minimumZoomScale = targetHeight / imageHeight;
scrollView.clipsToBounds = YES;
self.imageView = tempImageView;
[tempImageView release];
[scrollView addSubview:imageView];
scrollView.zoomScale = scrollView.minimumZoomScale;}
A new UIImageView is added each time to the UIScrollView and when the view disappears the UIImageView is removed. The zoomScale is calculated so that the image fits according to the aspect ratio.
Now to my problem the first time an item is clicked everything works fine and the map image fills the full height of the UIScrollView, but the next time an item is clicked the height of the UIScrollView is smaller. I also should note that the main window contains a tab bar.
So now to my questions:
How can the UIScrollView change it's size?
And is there any other dynamic way to retrieve the targetHeight?
Thanks in advance!
I was having a similar problem. It turns out the issue was that I was subclassing UIScrollView for the main view of my UIViewController, and the UIViewController had its own ideas about the correct size of the scroll view.
I fixed it by making the main view subclass UIView rather than UIScrollView, then adding a UIScrollView* content_view to the view, and adding my subviews to content_view rather than to self.
Not sure if this helps you or not, however...
Ok, i managed to found a solution my self, maybe not the best but it's dynamic and it works.
But i still don't understand why the height of UIScrollView would change. If someone know why please comment.
NSInteger scrollViewHeight = 0;
- (void)showMap {
if (scrollViewHeight == 0) {
scrollViewHeight = scrollView.frame.size.height;
} else {
scrollView.frame.size.height = scrollViewHeight;
}
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:mapImage]];
float imageWidth = tempImageView.image.size.width;
float imageHeight = tempImageView.image.size.height;
float targetWidth = scrollView.frame.size.width;
float targetHeight = scrollViewHeight - mapNavigationController.navigationBar.frame.size.height;
float scale = targetHeight / imageHeight;
if (scale * imageWidth < targetWidth) {
scale = targetWidth / imageWidth;
}
scrollView.contentSize = tempImageView.image.size;
scrollView.maximumZoomScale = 1.0;
scrollView.minimumZoomScale = scale;
scrollView.clipsToBounds = YES;
self.imageView = tempImageView;
[tempImageView release];
[scrollView addSubview:imageView];
scrollView.zoomScale = scale;}
}

UIImageView change Width and Height

I've read various posts on here asking similar questions... I've tried various ways that were posted including bounds and frames etc. including the following:
myImage.frame = CGRectMake(0.0f, 0.0f,50.0f, 50.0f);
and:
myImage.bounds = CGRectMake(0.0f, 0.0f,50.0f, 120.0f);
neither of those work.
However, I find it interesting that the following code let's me move the Image around but doesn't change the width:
CGRect frameRect = myImage.frame;
frameRect.size.width = 50.0f;
frameRect.origin.x += 10.5f;
myImage.frame = frameRect;
So why don't any of these change the width/height of my ImageView?
I found another post on here that basically states I have to right a small book of code to get it resize my image... is that true?
Such as this one:
UIImage: Resize, then Crop
certainly this is simpler than that??
The following will change the size of the UIImaveView, clipping the underlying image without resizing it and keeping it aligned to bottom left of view:
imageView.frame = CGRectMake(
imageView.frame.origin.x,
imageView.frame.origin.y, newWidth, newHeight);
imageView.contentMode = UIViewContentModeBottomLeft; // This determines position of image
imageView.clipsToBounds = YES;
First off, you can't set the frame or bounds of the UIImage - that will only work on a UIImageView.
I've found that changing the frame of a UIImageView causes the Image to be scaled to the new size. Sometimes, that's undesirable - and you want instead to crop the image.
I can't tell if this is what you're asking for, but here's some code to crop an image to a specific size in a UIImageView:
UIImage *myImage = [UIImage imageNamed:#"photo.png"];
CGRect cropRect = CGRectMake(0.0, 0.0, 320.0, 44.0));
CGImageRef croppedImage = CGImageCreateWithImageInRect([myImage CGImage], cropRect);
UIImageView *myImageView = [[UIImageView alloc] initWithFrame:cropRect];
[myImageView setImage:[UIImage imageWithCGImage:croppedImage]];
CGImageRelease(croppedImage);
From what I get of the question, the OP wanted to change the size of the UIImageView when the size of the container UIView is changed. The code below will do it...
UIView * foo = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)] autorelease];
foo.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
UIImageView * bar = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"test.png"]];
bar.autoresizingMask = foo.autoresizingMask;
[foo addSubview:bar];
[self.view addSubview:foo];
The key here are the foo.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight and the bar.autoresizingMask = foo.autoresizingMask; lines. Forget either of these, and the whole jigmarole will stop working.
Well, if your read the documentation about UIIMage you can notice that is impossible to change any parameter of an UIImage after create it, the solution I've implemented for use high quality images for change some parameter of (for example) the SliderControl as Screw Image, is the next one:
UIImage *tumbImage= [UIImage imageNamed:#"screw.png"];
UIImage *screw = [UIImage imageWithData:UIImagePNGRepresentation(tumbImage) scale:2];
With that, I can to use 100x100 px image in my apps scaled to 50%.
Kind regards.
Try Using a UIScrollView. Add the UIImageView to the UIScrollView in Interface Builder you can then control the position and size of the image as follows:
CGRect rect = [scrollView frame];
rect.origin.x = 50.0f;
rect.origin.y = 0.0f;
rect.size.width = 320.0f;
rect.size.height = 150.0f;
[scrollView setFrame:rect];
If you tried those methods cannot work, the only way to do it is to add the constraint of width and height to the UIImageView.
// Create the constraint in code
NSLayoutConstraint *constraint0 = [NSLayoutConstraint constraintWithItem: myImage attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1.0f constant: yourNewsWidth];
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem: myImage attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1.0f constant: yourNewsHeight];
[myImage addConstraint:constraint0];
[myImage addConstraint:constraint1];
Use myImageView.frame = myNewPosAndSize; to resize or reposition your image view (as with any other view). It might confuse you that the image view draws its image with its original size, possibly exceeding its own dimensions. To disable this use myImageView.clipsToBounds = NO;
You don't have to write a whole book, you can copy that code.
I believe the UIImageView always draws the image at 0,0 at a 1.0 scale. You'll need to resize the image if you want to continue using the UIImageView.