preventing a specific view from auto rotating... is that possible? - iphone

I have a view based app. Its self.view has several subviews and shouldAutorotateToInterfaceOrientation is returning YES.
When I rotate the device, all views rotate as expected.
Is that possible to prevent a subview from auto rotating even if the view's parent is auto rotating?

Keep in mind that it's the view controller that controls what happens during rotation and not the view itself. You can't stop a subview from rotating by setting a property, or something relatively easy, if its parent view's UIViewController is set to auto rotate. You can, however, have sibling views where one rotates and the other doesn't. It's probably possible to layout your views the way you want but not have the one that shouldn't rotate as a subview of a rotating UIViewController.
You could probably write some code that will reorient a subview so it appears not to rotate when the parent view does rotate, however.

Related

iOS Uniform scale subviews with superview

I have an app that allows a user to drag views onto the screen in multiple orientations. So lets say i'm in portrait mode and my superview is 768x1024. Lets say I drag 10 different items onto that superview. These items are scaled, rotated, etc. Then I rotate the device and my superview shrinks down to 576x768. How do I get all of my subviews to maintain their position and transform relative to the new smaller size? So in essence my superview and all of its subviews should look exactly as they did while in portrait, except everything has been scaled down.
And also, what if im in landscape and everything is "shrunk" down and then I drag another view on and shrink it down to fit well. I would need that new view to scale up in proper place and size when the device is rotated back into portrait
The easiest thing to do here is to use the transform property of your view. In this case, you'd prevent the view from auto-resizing on rotation, and use something like your view controller's willAnimateRotationToInterfaceOrientation:duration: method to set a transform on your superview. You can create a transform with CGAffineTransformMakeScale that will scale up or down all of your content; you'll probably want one for landscape and just use a nil transform for portrait (or vice-versa).
This will complicate dragging new views into your superview, since it's transformed, but once you've got views in there, they should behave correctly when resizing. For new views, you'll have to compute (perhaps using convertRect:fromView: method of UIView) what a rect will be once you add a new subview.
You can also override your view's layoutSubviews() directly and assign your subview's transforms based on your view's dimension. This way, you can still get the benefits of using Auto Layout with your view and potentially other sibling UI items, while you customize subview's frames and/or transforms manually without Auto Layout.

Why do I have to reposition this UIView by an arbitrary amount?

I am building an application that must add an overlay view once a scrollview is done zooming. I was having problems adding the overlay to the scrollview itself and keeping the position consistent, due to what I assume is the scrollview not being done zooming...no biggie...so I decided to add the overlay to the sharedApplication's keyWindow.
Now, the application is in landscape orientation, and I have to do a transform on the overlay to get it to orient properly...this is fine. The issue arises in having to reposition the overlay by this seemingly arbitrary amount to get it centered...I dislike doing things ad hoc like this, so I thought I'd ask if anyone has run into something like this, and why the view has to be repositioned by this strange offset. Any insight would be great.
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI/2);
tempOverlay.view.transform = transform;
// Repositions and resizes the view.
CGRect contentRect = CGRectMake(-107, -80, 480, 320); //where does this offset come from?!?
tempOverlay.view.bounds = contentRect;
[[[UIApplication sharedApplication] keyWindow] addSubview:tempOverlay.view];
I was going to post this as a comment instead of an answer originally, but I'll just go for the answer route instead, even though I don't think there's really enough information to go on here. The following assumes that you have a fairly standard iOS application, aside from this overlay oddity where you're attaching the view to the keyWindow.
First, don't attach add your overlay view to the keyWindow. Instead, define some method on your root view controller which requests the overlay be displayed. Then in your root view controller code, add the overlay view to the controller's view above everything else.
Then, don't apply the transform since it will no longer be necessary to rotate your view.
At the time you create your view, set it's frame to be the bounds of the root controller's view. Also set it to have a flexible width and height via the autoresizingMask of UIView. Then assuming your root UIView has it's autoresizesSubview property set to YES, your overlay view will be nicely resized to match the size of the root view as it changes orientation.
If after all this the position of the contents of your overlay UIView is incorrect then I suspect the problem is within the contents of that UIView and has nothing to do with the need for any magic numbers in your frame/bounds.
NOTE: I haven't actually tried the above and am not 100% confident that in general your root UIView will enjoy having this extra overlay UIView thrown on top of it, on the other hand, it might remain blissfully unaware of it and everything will Just Work. Either way, to me it feels a lot less 'ad hoc' than what you're currently trying to do.

iPhone/iOS SDK: Autorotate main view, but not child view?

Here's what I'm trying to do.
I have a single view ("primaryView"), controlled by a customized view controller. primaryView contains a scrollview, which contains an image. Sitting on top of the scroll view (NOT inside it) is a small view ("buttonsView") containing a few buttons.
Basically, when the user rotates the phone, I want buttonsView to autorotate to match the new orientation, but I want the scrollview to remain exactly as it is, and NOT rotate.
Is there a way to do this? Right now, primaryView is autorotating, and taking both subviews (the scrollview and buttonsView) with it, which is no good.
Thanks!
The system will not autorotate unless all visible views consent to autorotation. What you can do, then, is to detect orientation changes, and set an appropriate affine transform for the non-rotating views, essentially to undo the system's rotation.
You can use willRotateToInterfaceOrientation:duration: to fade out the controls, then didRotateFromInterfaceOrientation: to fade them back in at the correct location.

UIView Subview Does not autoresize on orientation change

In my iPhone app, I have a view controller with two views (essentially, a front & back view). The front view is the main UIView, and the back view is a secondary UIView which is added as a subview using [self.view addSubview:backView] when showing the back and [backView removeFromSuperview] when hiding it. However, when the orientation changes, I have the following issue: the main UIView (frontView) rotates & all of its elements resize properly, but the secondary/subview UIView (backView) does not rotate & all of its elements do not resize properly. Does anyone have suggestions on how to make the secondary UIView autoresize properly according to the rules I have set in Interface Builder?
In the end, the solution I found was simply to separate my UIViews into separate UIViewControllers, and make sure that any views that I wanted to be able to rotate only had one UIView.
If I understand correctly, at the time of rotation 'backView' has been removed from it's superview, yeah? If so, that's the cause of the problem. The autoresize property determines how the view resizes relative to it's superview. If it doesn't have a superview it won't resize.
Perhaps using [backView setHidden:YES] instead of [backView removeFromSuperview] will be sufficient for your needs.
I had the same problem, here is how I fixed it based on imaginaryboy's
suggestions (thanks!)
Add the backview to the viewcontroller at viewDidLoad and hide it at the same time. Show it when needed, Hide it again. Set the resizing of the backview to UIViewAutoresizingFlexibleWidth in IB (or code I guess, I used IB)
Not that this is the same problem, but I found a similar problem when adding 2 subviews in my application:didFinishLaunchingWithOptions method. Since your reference above is using [self.view addSubview:view], I would understand that to mean that self is not your UIWindow. When adding an additional view controller to your App Delegate window (UIWindow), the second view controller will NOT receive any rotation events and will never rotate. Only the first view controller added to UIWindow will rotate. See:Technical Q&A QA1688 I believe this also affects views added after the first view where the first view is later removed from the superview.
I ended up following the suggestion I read elsewhere to use separate views for each orientation, thereby eliminating the need to worry about resizing behavior. As always, YMMV.
Or; if you want to avoid an additional controller, you can achieve the same effect by setting view.frame in willRotateToInterfaceOrientation:: like so
if(UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) ;//set stubborn view.frame for landscape orientation
else ; //set stubborn view.frame for portrait orientation
Although it feels like a hack; it's simple.

CATransition how to clip to bounds of UIView?

I'm using CATransition to slide subviews of UIView. But the problem is that the CATransition always appears in whole screen. And it looks like a mess because I have another UI elements in window that become overlapped while transitioning. How can I restrict frame of transition by UIView frame? I tried to set clipToBounds of my UIView to YES. Actually it doesn't help.
I'm not really 100% sure about this, but I think you're wrong about CATransition applying to the whole screen. It applies to the view you add the animation to.
The idea is that you apply the transition to the parent of the view you actually want to transition. So say you have the following structure.
UIViewController
view (main view of UIViewController)
view you're transitioning
What you need to do is add a "holding" or "container" view between the main UIViewController view and your actual targeted view, such that it looks like this:
UIViewController
view (main view of UIViewController)
"container" view <-- Apply transition here
view you're transitioning
Apply your transition to the container view and you'll be able to clip it, if you want. If it still goes out of bounds, then try turning on clipsToBounds on the containing view, or the layer's masksToBounds property