CGAffineTransformMakeRotation and UIViewController Rotation predicament - iphone

I've got a problem.
I've an UIImageView and i do some rotation to it with CGAffineTransformMakeRotation().
Not problem with that.
But when i do a rotation with my UIViewController (portrait to landscape and/or inverse).
My UIImageView is modified strangely.
Its frame become change from :CGRectMake(50.f, 50.f, 150.f, 150.f)
to a frame like :CGRectMake(50.f, 123.2f, 1004.56f, 1530.456f)
I realize that changes happens when I do UIViewController rotation when i've done a rotation on my UIImageView not equal to 0, 90, 180, or 270
I think it's because the UIViewController change the rect of the UIImageView but how inhibit
that comportement
Unfortunately my view move/change visually.
That's my problem and why I'm talking about that here...
I spoke about the frame property because I notice it changed strangely (and randomly) and even if I changed it after to my original frame. The view doesn't seem 'listen' to it.
I hope I am well.
Anyone for a solution ?

If you set a view's transform property to anything but the identity matrix (which you must have done in order to rotate it), the frame property becomes undefined and should be ignored. This is noted in the documentation. Is it just the frame property that goes wrong or is the view moving/changing visually in some unexpected way as well?

It's not clear from your description, but it sounds as if your UIImageView is a subview of the view owned by your UIViewController. Unless you have a reason to not manage it this way, I'd suggest setting the UIImageView struts and springs (i.e., its autoresizingMask) to surface the desired behavior and then allow the parent view to reposition/resize the UIImageView.

Related

How to get the correct frame of a rotated UIView (including correct position)

I have an app where I have a rectangle that the user can rotate and pan using their fingers. I'd simply like to know what the frame is of this rotated view so I can find out if it intersects another rectangular UIView (can't use the frame property because it gets invalidated when the UIView gets transformed). What's the easiest way to accomplish this?
Every UIView has a property frame which is of type CGRect.
You can access it using view.frame.
After the transform is applied you can use the bounds and center property on the view to get the orientation. It may take a little bit of calculation but i hope you can get to it easily.
Refer to this image from an answer to this question.

UIScrollView made in storyboard has frame value of zero

I made a scrollview in my storyboard which contains severals UIImageView.
The problem is, the frame of that scrollview is equal to {0, 0, 0, 0} and I don't know why. The scrollview is visible on my screen, but I'm not able to scroll it.
I already try to set a content size, and a frame, but without success.
Fixed it out !
In fact, I develop the app on iOS 6.0 and I had to uncheck the "use autolayout" checkbox on storyboard properties...
Thanks to all anyway !
I was getting this problem too but I need to use auto layout.
I was trying to set an UIImageView as a subview then do some calcs to work out the minimum, maximum zoom scales and set the zoomScale.
The problem was that I was trying to set zoomScale to zero as the scroll views frame was zero which was giving me this error:
<Error>: CGAffineTransformInvert: singular matrix.
So I setup the image and imageView in viewDidLoad / viewWillAppear (and hide the imageView) and then set the zoomScale in viewDidAppear (then unhide imageView).
This seems to work well, although I can't say for sure why. I guess it gives the scroll view a chance to set its bounds correctly.
The issue here is AutoLayout, as some of the other answers have indicated. Specifically, the issue is that autolayout does not occur until after viewWillAppear, and if you put your code in viewDidAppear, you will get funky display artifacts as you change things on the screen while the user is watching...
If you need AutoLayout enabled, the best place to put your frame dependent code is in:
- (void)viewDidLayoutSubviews
Keep in mind that this gets called again and again though, so if you only want some initialization code run once, when the view is displayed, then you can create a BOOL property that stores whether the initial layout has already been done.
#property (assign, nonatomic) BOOL initialLayoutComplete;
And then you can write your viewDidLayoutSubviews this way:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (!self.initialLayoutComplete) {
// frame dependent code here...
}
}
As I mentioned in this answer: The frame of the scrollview will not be initialised until you are in the viewWillAppear method.
This seems to be a new behaviour in iOS 6, not sure if it's a bug or an intentional change.
You should be able to use auto layout without worrying about this.
Did you connect IBOutlet?
Did you init scrollView with this code:
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 280, 360)];
self.scrollView.contentSize = CGSizeMake(500, 360);
//values are of course only example values
How you add UIImageView to scrollView?
I think one clarification is in place to Enrico comment below.
The frame size will have the right values at viewDidAppear (and in viewWillAppear the value will be set, but they are still zero in that method)

How to animate from UiImageView to a UIView

I use Path2.0. I have found that when I click the small picture in a message,there would be an animation to show the whole picture. How does it do that?
I would really appreciate help here. Thanks!
UiImageView is bascially a UIView, which you can apply animation on.
The use case you want to achieve combines:
a. a response to touch event, which you can use UITapGestureRecoginizer to attache a block of code
b. zoom the UIImageView into a proper size and position, you can use UIView's class method AnimiationWithDuration....
c. Ultimately, you want to change your UIImageView's frame property to a larger one. use CGRectMake to generate a new one. If you need to take the whole screen estate (like Path 2.0 does), you may need [UIApplication sharedApplication].window for this
I doubt they modify the original UIImageView; but a solution might be:
Copy the UIImageView (or UIImage)
Add it as a subview with the same exact frame as the original image
Apply a scale transform on the UIImageView (by using the CGAffineTransformMakeScale() function on a UIView's transform property (inside a UIView animation block)
Then instantiate the root window with a scaled version of the full image
Alternatively, you could instantiate the new subview with the full image, set it with the original UIImageView's frame, and then (using a UIView animation block), set it to the newer frame. To match their implementation exactly, I suggest a black subview (of the full UIImageView) with an alpha of 0.0 that you then animate at the same duration to an alpha of 1.0.

How do I get a UIView which displays text to behave like a UILabel when bounds change?

I have a UIView in which I need to draw text in drawRect:
- (void)drawRect:(CGRect)rect {
...
[#"some text" drawAtPoint:somePoint withFont:someFont];
...
}
Because the text requires special formatting, I cannot just use a UILabel.
It looks fine until I rotate the device. Then the size of my custom UIView changes (in the parent view's layoutSubviews method), and the text becomes stretched in one direction and squished in the other.
When I replace my view with a UILabel, the text always looks great, even when the bounds of the view changes.
How can I get my view to exhibit the same behavior as UILabel?
Some things I have looked into, but have yet to have success with:
Set the view's layer's needsDisplayOnBoundsChange to YES.
Set the view's contentStretch to CGRectZero.
Call setNeedsDisplay in my view's layoutSubviews.
Maybe I'm not doing one of these things right. Has anyone else run into this?
Update: As recommended in James Huddleston's answer, I set the contentMode property of the view to UIViewContentModeRedraw, which got me part of the way there. The text now appears correct at the conclusion of the animation. However, at the start of the animation the text gets squished/stretched to fit the end dimensions and then gets unsquished/unstretched over the course of the animation. This is not the case with UILabel.
Try setting the contentMode property of your view to UIViewContentModeRedraw.
This seems to work OK:
self.contentMode = UIViewContentModeRedraw;
self.contentStretch = CGRectMake(1, 1, 0.5, 0.5);
And then ensure that the bottom-right pixel is the background color. To do that, I put one pixel of padding around the contents of the view. It seems like UILabel doesn't have the one pixel border restriction, so it must be doing something different. But as far as I can tell, this has the same effect.
Use a UIWebView
Sounds a bit overkill but it seems the recommended way to get formatted text that's more complicated than a UILabel can cope with.
There is some source code created by Kevin Ballard called FontLabel. (code.google.com)
The good thing about this, it subclasses UILabel and you can use your own Font ;)
//EDIT: ok ok, as told I will update my answer to recommend subclassing UILabel "to get all the UILabel goodness" ^^

How to auto rotate your own custom views?

I've learned that the best way to get graceful rotation is to set the auto rotation mask on the view that you want resize or move. This works fine if you're using SDK views like UILabel, but if you have your own custom view that uses the drawRect method it doesn't rotate as gracefully. In fact the only thing that happens is that it stretches whatever you drew in drawRect.
I've tried redrawing both before and after the rotation, but it doesn't give me that smooth rotation.
I looked at a UITextField auto rotating (flexible width) in slow motion and it follows the edge perfectly during the rotation. That is what I want my view to do, so how do I do that? My views jump to the right position either before or after the rotation.
The following line will make your UIView stretch the middle pixel only. If this is not your desired behavior I suggest you read the documentation for contentStretch to learn how to manipulate the values of the CGRect.
[self setContentStretch:CGRectMake(0.5, 0.5, 0.0, 0.0)];
I would guess that the UITextField you're looking at has at least three subviews, one displaying the left cap of the field's border, one displaying the right cap, and one displaying the middle, with autoresizing masks of "flexible right margin", "flexible left margin", and "flexible width", respectively. If you set up your custom view something like that, and make sure its autoresizesSubviews property is set to YES, then you should get the same smooth resize that the text field does.