Animating the cropping of UIView/ UIImageView - iphone

I have this chunk of code which is placed in accelerometer: didAccelerate which changes the cropping of an image. Basically as you tilt an iPad an image gets truncated (not resized) which is exactly the effect I'm looking for. Note: self.xPos is effected by the position of accelerometer.x.
UIImage *originalStringImage = [UIImage imageNamed:#"string.png"];
CGImageRef imageRef = CGImageCreateWithImageInRect([originalStringImage CGImage], CGRectMake(0.0f,0.0f, self.xPos+50.0f, 26.0f));
[self.stringImageView setImage:[UIImage imageWithCGImage:imageRef]];
self.stringImageView.frame = CGRectMake(10.0f, self.stringYPos, self.xPos+50.0f, 26.0f);
Now I would like to do the exact same thing, although as a UIView animation. Something between these UIView animation parameters:
UIImageView *pageStringImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10.0f, placeString, 0.0f, 42.0f)];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelay:2.0];
[UIView setAnimationDuration:3.0];
pageStringImageView.frame = CGRectMake(10.0f, placeString, 900.0f, 42.0f);
UIImage *originalStringImage = [UIImage imageNamed:#"string.png"];
CGImageRef imageRef = CGImageCreateWithImageInRect([originalStringImage CGImage], CGRectMake(10.0f,placeString, pageStringImageView.frame.origin.x, 42.0f));
[pageStringImageView setImage:[UIImage imageWithCGImage:imageRef]];
[UIView commitAnimations];
But the above doesn't work it all. In fact it doesn't even show the image. I believe the main difficulty here is changing the size of the image dynamically while the UIView animation is running.
Any suggestions or questions?

This should be fairly simple to do if you use the scaling properties of your UIImageView (the .contentMode property).
Views - including image views - can display there content in a number of ways. The default for an image view is to scale the content, so when you change the frame/bounds of the image it shrinks / expands as appropriate.
So if you were to use a standard UIView animation block to adjust the frame of a UIImageView it would animate the image scaling or shrinking. But if you change the image view's .contentMode property if you change the frame you can have it crop instead.
For example, UIViewContentModeLeft will align the content with the left hand side of the view, so if you adjust the width of the view it will be 'cropped' from the right side. Check the UIView documentation to see all the values you can have for contentMode. So basically, just animate your view's frame changing, but set the contentMode appropriately to give you the desired cropping effect. You may need to make sure your view is set to clip to bounds, although I have a feeling image views do this by default.

Related

why the image become zoom while converting view to image?

I have uiview and i want to convert that view to image which is working quite well but when i pressed the home button of iphone and run the app again the image become zoom in .Here is my code to converting view to image.
- (UIImage *)captureView {
CGRect rect = [myview bounds];
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[myview.layer renderInContext:context];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
checkImage.image = [self captureView];
here this code is not wrong but you used some other object instead of whole view . i don't know but try to use that view bounds in which that whole Image display.. See my answer same like your this answer from this bellow link..
how to capture uiview top uiview
Also try with self.view instead of myView in your code.
add this code instead of your checkImage.image = [self captureView]; line..
UIImageView *imgTempHeader = [[UIImageView alloc]initWithImage:[self captureView]];
imgTempHeader.frame = self.view.frame;
[self.view addSubview:imgTempHeader];
[self.view bringSubviewToFront:imgTempHeader];
You should be creating the context in a way which uses the scale of the device:
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
Then when you display the image in the image view ensure that the content mode is set to prevent scaling.
My experience is with setting up imageViews in IB. I assume checkImage is an instance of UIImageView?
If you were displaying an image in a UIImageView and had only set the view mode to center in interface builder it would appear zoomed in if the image was large.
Have a look at this way to process your image first:
UIImage *newImage = [[UIImage alloc] initWithCGImage:myCGImageRef scale:myZoomSCale orientation:UIImageOrientationDown];
Of course you will need to give it a CGImageRef for your image. Over to you or somebody else for that.

What type of contents UIViewContentMode mode refers to?

According to the official doc on UIView about the contentMode property:
The content mode specifies how the cached bitmap of the view’s layer is adjusted when the view’s bounds change
What's defined the content in this definition? Is it a sub view or when we have define a background color for a view for example.
My very first guess was that it should apply at least for the subviews in a view, but for example the following code snippet will not give me the expected result when playing with the UIViewContentModeCenter tag:
UIView* redView = [[UIView alloc] initWithFrame:CGRectMake(80, 80, 150, 200)];
redView.contentMode = UIViewContentModeCenter;
redView.backgroundColor = [UIColor redColor];
UIView* greenView = [[UIView alloc] initWithFrame:redView.bounds];
greenView.backgroundColor = [UIColor greenColor];
[redView addSubview:greenView];
redView.frame = CGRectInset(redView.frame, -5, -5);
[self.view addSubview:redView];
I have just set up a redView that will include a greenView. I have also set-up the content mode of the redview to UIViewContentModeCenter - why in the code I wrote the greenView is not centered when I change the frame of its parent? isn't what UIViewContentModeCenter is supposed to do?
Thanks for clarifying!
Ps: You can easily test the above code in the loadView of a simple view controller template project.
From the documentation:
The content mode specifies how the cached bitmap of the view’s layer
is adjusted when the view’s bounds change.
For an image view, this is talking about the image. For a view that
draws its content, this is talking about the drawn content. It does
not affect the layout of subviews.
You need to look at the autoresizing masks in place on the subviews.
Content mode is a red herring here. If you can't achieve the layout
you need using autoresizing masks, then you need to implement
layoutSubviews and calculate the subview positions and frames
manually.
from jrturton's answer to: https://stackoverflow.com/a/14111480/1374512
First read about Content Modes here
In your example you change the frame of the red view. That will invoke layoutSubviews on the view which will reposition the green view according to the layout constraints or autoresizing masks. You haven't specified any. So the frame of the green view will stay the same.
The content mode specifies how the view's layer should update when resizing. Depending on the content mode drawRect will be called or not.
You can test the effect of the different content modes with the following example:
Add a UIView subclass, that draws a circle using this drawRect implementation:
- (void)drawRect:(CGRect)rect
{
// Drawing code
NSLog(#"drawRect %#", NSStringFromCGRect(rect));
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, self.bounds);
[[UIColor redColor] setFill];
CGContextFillPath(ctx);
}
In the view controller create and add the circle view:
CircleView* circleView = [[CircleView alloc] initWithFrame:CGRectMake(10, 10, 20, 20)];
circleView.contentMode = UIViewContentModeCenter; // <- try different modes here
[self.view addSubview:circleView];
Now lets animate the frame and see what happens:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:5 animations:^{
circleView.frame = CGRectMake(10, 10, 100, 200);
}];
});
I'm doing that asynchronously to force CoreGraphics to draw the view at least one time with the original frame.
When you don't set the content mode you end up with a blurry circle, because it just scales up without redrawing. UIViewContentModeCenter makes the small circle stay at the center - also no redraw needed. UIViewContentModeRedraw makes the view draw the view again with the new frame. Actually that happens before the animation starts.
Note that the content mode can affect the drawing performance.

Objective-C: AutoresizingMask + 2 Subviews = struggling

Solution: For those who view this someday in the future, the solution I used was indeed viewDidLayoutSubviews. The solution was actually rather complex - I had to calculate several scaling values and dynamically re-size the Art view every time the page needed a re-layout. There were several odd problems to handle, but after each was taken down the implementation feels pretty solid.
If anybody runs in to a similar problem later on, let me know and I can post the relevant code.
I've got a 'blank' UIView, a subview that is an UIImageView containing a single image, and a second subview that is basically a collection of CGContext arcs and lines and all that.
Where I'm at: I've placed the UIImageView subview on top of the UIView so that its image is the 'background'. Then I placed the CGContext arcs and lines subview on top of that (I'll call this the Art subview for clarity). All good. Everything displays perfectly and aligned.
Problem: When I rotate, things get screwy. The arcs and lines on the Art subview end up at the wrong coordinates, and depending on my autoresizingmask settings the image gets stretched, etc. I can fix one of these problems at a time, but I can't find the right combination to fix them both!
Things I've Tried: I've tried just about every autoresizingMask option & combination of options, but per above I can't quite lick the problem with those. Given that I also tried using some custom code in viewDidLayoutSubviews, but this felt really flimsy and much less extensible vs. using autoresizingMasks. So I abandoned the path after making some nominal progress.
What I've Learned: As long as I bind my UIImageView frame and the Art subview frame to the same dimensions, then the arcs and lines stay at the proper coordinates. That is probably the easiest way to state my goal: to have a UIImageView that stays in the correct aspect ratio (not just the image within, but the view itself), and then match the Art subview exactly to its frame - even as the screen rotates, etc.
Here is a diagram of what I'd like to achieve:
+ = UIView
~ = UIImageView subview
. = Art subview
Portrait
Wherein the image within the UIImageView takes up basically the whole screen (though not quite), and the Art subview is layered on top of it with the dots below representing a crude line/arc.
++++++++++
+~~~~~~~~+
+~ . ~+
+~ . ~+
+~ . ~+
+~ . ~+
+~~~~~~~~+
++++++++++
Landscape
Wherein the UIImageView sublayer maintains its aspect ratio, and the Art sublayer stays 'locked' to the image within the UIImageView.
++++++++++++++++++++++++++
+ ~~~~~~~~ +
+ ~ . ~ +
+ ~ . ~ +
+ ~ . ~ +
+ ~ . ~ +
+ ~~~~~~~~ +
++++++++++++++++++++++++++
My View Controller (where I think the problem is - also removed all autoresizingMask settings to clean up the code)
- (void)viewWillAppear:(BOOL)animated {
// get main screen bounds & adjust to include apple status bar
CGRect frame = [[UIScreen mainScreen] applicationFrame];
// get image - this code would be meaningless to show, but suffice to say it works
UIImage *image = [.. custom method to get image from my image store ..];
// custom method to resize image to screen; see method below
image = [self resizeImageForScreen:image];
// create imageView and give it basic setup
imageView = [[UIImageView alloc] initWithImage:image];
[imageView setUserInteractionEnabled:YES];
[imageView setFrame:CGRectMake(0,
0,
image.size.width,
image.size.height)];
[imageView setCenter:CGPointMake(frame.size.width / 2,
frame.size.height / 2)];
[[self view] addSubview:imageView];
// now put the Art subview on top of it
// (customArtView is a subclass of UIView where I handle the drawing code)
artView = [[customArtView alloc] initWithFrame:imageView.frame];
[[self view] addSubview:artView];
}
the resizeImageForScreen: method (this seems to be working fine, but I figured I'd include it anyway)
- (UIImage *)resizeImageForScreen:(UIImage *)img {
// get main screen bounds & adjust to include apple status bar
CGRect frame = [[UIScreen mainScreen] applicationFrame];
// get image
UIImage *image = img;
// resize image if needed
if (image.size.width > frame.size.width || image.size.height > frame.size.height) {
// Figure out a scaling ratio to make sure we maintain the same aspect ratio
float ratio = MIN(frame.size.width / image.size.width, frame.size.height / image.size.height);
CGRect newImageRect;
newImageRect.size.width = ratio * image.size.width;
newImageRect.size.height = ratio * image.size.height;
newImageRect.origin.x = 0;
newImageRect.origin.y = 0;
// Create a transparent context # the newImageRect size & no scaling
UIGraphicsBeginImageContextWithOptions(newImageRect.size, NO, 0.0);
// Draw the image within it (drawInRect will scale the image for us)
[image drawInRect:newImageRect];
// for now just re-assigning i since i don't need the big one
image = UIGraphicsGetImageFromCurrentImageContext();
// Cleanup image context resources; we're done!
UIGraphicsEndImageContext();
}
return image;
}
There is no combination of autoresizing flags and content modes that will do what you want. Using viewDidLayoutSubviews is one reasonable way to handle the layout. That's why it exists: the autoresizing flags are pretty limited.
A different approach is to change your -[ArtView drawRect:] method so that the autoresizing flags can do what you want. You can make your drawRect: method implement the same algorithm that UIImageView implements for UIViewContentModeScaleAspectFit.

Programmatically prevent UIImageView from autoresizing

I would like to truncate one end of a UIImageView by changing the size of the frame dynamically. Of course, if it autoresizes it won't look 'truncated', but will look shrunk. The former is the effect I would like, the latter not.
So far I've set up the UIImageView in IB and then hooked it up programmatically using IBOutlet. I then placed this in ViewDidLoad, but still get the autoresizing:
[self.stringImageView setAutoresizingMask:UIViewAutoresizingNone];
self.stringImageView.frame = CGRectMake(9.0f, 508.0f, 500.0f, 26.0f);
Any ideas how I can clip my UIImageView instead of having it resize?
EDIT 1
It should also be noted that in IB I have deselected Clip Subviews and Autoresize Subviews.
Use : stringImageView.contentMode = UIViewContentModeCenter; so the image you add to the UIImageView always keeps the same size and the same position in your view.
You need to clip the UIImage object first according to imageview's frame and then set it as image for image view. See also Cropping an UIImage
#implementation UIImage (Resize)
// Returns a copy of this image that is cropped to the given bounds.
// The bounds will be adjusted using CGRectIntegral.
// This method ignores the image's imageOrientation setting.
- (UIImage *)croppedImage:(CGRect)bounds {
CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return croppedImage;
}
In Interface Builder set Mode in the View Tab to "Top" or whatever it should be.
Another more efficient way to go if you only wish to make part of the image visible,
or for example animate its appearance,
is to set the content mode of the UIImageView to UIViewContentModeCenter (or any other alignment) and include it in a UIScrollView.
You will only need to change the frame of the scroll view and your image will be visually cropped without you having to create the cropped image (which would be a very high price if it is for animation purpose).

How to stretch the image size in iphone UIImage or UIImageView

I'd like to show an image in an iPhone app, but the image I'm using is too big.
I'd like to scale it to fit the iPhone screen, I can't find any class to handle it.
UIImageView* view = [[UIImageView alloc] initWithImage: [UIImage imageNamed: #"your_image.png"]];
view.frame = CGRectMake(0, 0, width, height);
To get the frame of the iPhone screen you can use
CGRect frame = [[UIScreen mainScreen] bounds];
In Interface Builder, select your UIImageView. From the Tools menu, select "Attribute Inspector". In the Image View Attributes palette, select "Scale to Fill" from the Mode popup. That should scale your image to fit.
My ImageView was set in IB, and I would need to show multiple images, so set the image of imageView, instead of creating ImageView for individual image.
After I set the image view frame size, I am still see the same result, the image was too big, so that only part of the image was displayed on the screen.