I’m trying to set up an iPad test application, window-based, where I have a single view controller and a single view. When I rotate the iPad, I want the orientation of the toolbar to change, but not that of the view itself. For example, a sort of background view that you work in is fixed to the device, but the status bar and toolbars rotate around it. This would enable the user to work the view from all angles, but always with a correctly-oriented toolset.
A beautiful implementation of what I want can be found in the Brushes for iPad app, where the painting’s orientation is locked to the device, and the toolbars rotate around it. I think other painting apps do the same thing.
I’ve been trying to figure out how to do this, but after exhausting many many other questions here concerning orientation, I’m still at a loss.
Could anyone point me in the right direction towards a neat solution? A particular combination of autoresizes for the autoresizeMask? Countering the rotation animation with another one in the opposite direction? Using multiple concurrent view controllers, one for the rotating views and one for the non-rotating ones?
I’d very much appreciate it,
(Edit: Attempted to clarify the question, after Olie’s comment.)
To prevent rotation, you'd put this in your view controller's .m:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
But you say you still want the view frame to resize in response to the rotation. I haven't had a need to do this myself, so I'm not sure if it's sufficient to just set the autoresizingMask to have flexible width and height; you may also have to implement didRotateFromInterfaceOrientation: and use setNeedsLayout and/or resize the view manually.
I had a bug that did this a while back -- I'm pretty sure that what you're asking will get you a HIG-violation rejection from Apple. However, I'll give a shot at remembering what the problem was. I'm pretty sure it was something like this:
I had a tabbarViewController that said "I orient to any orientation."
One of the tabs was a regular-old UIViewController that said "I only do LandscapeLeft & L-Right"
When you rotated, the inside (UIVC) stayed put, but the outside (TabVC) rotated around things.
I might have some of the details backwards or otherwise convoluted, but the general ideas is: stacked VCs, not all one VC.
Good luck!
To the extent I have worked with I cannot see any simple answer to your question. What about rotating everything (tabbar, nav and status bar, your view controller) and then redrawing the content of your view controller in "old coordinates" so for the user it will look like it's not rotated?
Related
I need to lock all controllers from auto rotation except one. It must rotates both portrait and landscape. I have read this topic and tried this solutions
let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
but I had no luck, it didnt work. Maybe this is because I use navigation controllers, I saw some mentions of them in previous link but I didnt understand approach because author allowed orientation modes in Xcode preferences and then duplicated them in code.
Maybe some one can help with advice ?
The current method to handle rotation is viewControllerWillTransitionToSize:withTransitionCoordinator:. Documentation is at this link: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIContentContainer_Ref/index.html#//apple_ref/occ/intfm/UIContentContainer/viewWillTransitionToSize:withTransitionCoordinator:
It's a little bit different because you're working with screen sizes not orientations. This is the new way of dealing with sizes and transitions. Think of it like a responsive layout instead of distinct rotation values. To put it a different way, you're not designing for "landscape orientation" anymore, but for a screen thats wider than it is tall. It's a subtle but important difference.
You could implement this method in different ways for different view controllers. If you're using a navigation controller and want to affect child views differently, first I'd say thats terrible UX most likely. But if you still want to do it, you could handle rotation in your Nav Controller.
You should not set the device orientation like that.
you can try this method. Paste this method on the view controller to make the device support portrait and landscape except upside down orientation.
func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMaskAllButUpsideDown
}
But as chris suggested, you should use viewControllerWillTransitionToSize and handle everything regarding the orientations there.
Lately Ive been working with moving my frame to make up for the 20point gap when the status bar is not showing in landscape mode. I have finally gotten what I want, yet there is one problem that kind of annoys me. Let me explain: First I was using a call in viewDidLoad to move the frame, but that doesn't do anything to the frame, because I suppose the frame gets drawn after viewDidLoad. So I tried placing my call in viewDidAppear. That works smoothly, but sadly the user "sees" the repositioning; you can watch the frame being replaced with the bare eye. So I was wondering if theres anything I can do to prevent this, any workarounds. (just for good explanation this call is to take care of view frame when the user updates/go to another view controller when already in landscape. I have other functions to take care of rotation; which obv works)
Any help appreciated. I tried to be as specific as possible.
Thanks!
I know this has been asked before, but none of these solutions work, and that's the reason of my posting. Please do not close before considering my case.
My plist already has UIViewControllerBasedStatusBarAppearance = false.
I have already tried applying deltas, but to no result.
Changing the top level view frame in ViewWillAppear (like self.view.frame) did not succeed.
I thought of increasing the view height (storyboard attribute inspector), in combination with deltas, but my top level view X, Y are disabled in storyboard attribute inspector.
My main view doesn't have any children views because I load them into main view either dynamically or load them from XIBs which are again shared by more than view controllers. These XIBs provide layout for both Portrait and Landscape. I don't know what approach is ideal for this kind of configuration, but I would like it better if solution lies along these lines.
This approach worked partially, but gave me inconsistent results.
What makes the solution tricky is the fact that I have to support all 4 orientations - this is something I handle in code via didRotate and willRotate delegates for my other views, but failing to do it for statusbar.
Please help...
Could this link be of any help?
You might have to use the new setEdgesForExtendedLayout: method to get this working consistently?
Also, have a look at these official docs if you haven't already done so.
I ended up writing my own function to shift my all subviews (remember, not top level views whose frame is fixated by IB).
It didn't spoil my work but imagine if this was the case for a very big project with so many screens, the limitations would have made it a nightmare.
I'm trying to design different layouts for my view controller. After googling, I've got this answer from SO. Basically, the answer instructs me to setup 2 scenes, one for landscape and one for portrait, when the device rotates, hide one and show the other one.
And my question is what if I want to add a sweet animation for the rotation process? For example, since I can setup the same view on different scenes, can I set the motion path for these views and disappear? Or, if it is easier, can I add some rotation and fade out animation?
I'm quite green with Core Animation, so a detailed explanation is very useful for me. Big big thanks in advance!
There are a few options here. The main methods you are looking for to do any of this are:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration;
and
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;
If you want to move the elements around the screen while the rotation is happening you will be best off changing the frames of the elements rather than creating a separate view file. Using any motion animation would require some mapping between the two and I have never heard of anything like this before. Again, if you just change the frames though, you can preform basically any screen movements you would like (for views and subviews).
To do the fading you could just throw an animation block in the first method:
[UIView animateWithDuration:duration
animations:^{
// set alphas for old and new views here.
}];
I've got a bit of a query on how certain views rotate when an iOS device changes orientation.
I'm developing an app right now, and it basically consists of 2 view controllers: the first being a UITableViewController embedded in a UINavigationController, the second being a completely custom one being built on a stock standard UIViewController.
I've noticed that on my UINavigationController view, when the device rotates, the UINavigationBar and the UIToolbar both perform a cross-fade animation when transitioning to their landscape dimensions.
For technical reasons, I didn't use a UINavigationController for my custom view controller, but I manually added a UINavigationBar and a UIToolbar in the same places to it (Basically because I need those elements to be able to be overlaid on top of the background view, as they can optionally be hidden and I wanted direct control to do that).
However, when I rotate my device when my custom view controller is visible, the two bars do NOT perform a cross-fade transition. Instead, all of the subviews slide around (looking a bit chaotic), and the background image distorts as it immediately gets swapped over to the iPhone landscape version before the animation actually starts (ie, so it starts off tiling the 32pt high artwork inside a 44pt high UIToolbar).
I was just wondering, does anyone now how Apple actually goes about creating this cross-fade blending effect for certain UIViews when the device orientation changes?
Don't use native auto-rotation rotate your view. Rotate them manually. Look the second answer here:http://stackoverflow.com/questions/1220580/iphone-dev-manually-rotate-view . Essentially you sign up for device rotation notification and do the view rotations yourself.
If you want to crossfade the two views in addition to the UIView animate block specified in the link above go:
[UIView transitionWithView:superViewOfButtonView duration:2.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[thebuttonViewIWantToCrossFade setFrame:newPositionRect];
}completion:^(BOOL finished){
//any completion code
}];
Let me know if this works for you!
I actually came back and re-explored this. While the UIView and CAAnimation transition methods do indeed work, their respective framerates on different iOS devices vary so wildly that I didn't think implementing them was the best solution.
I finally bit the bullet and contacted Apple Developer Relations and asked them directly (If you didn't know, each Mac/iOS developer may ask 2 questions to these guys for free each year!).
They replied promptly, and informed me that several Apple engineers actually presented a talk on that exact topic at WWDC 2012.
The talk was recorded, and is available to registered Apple developers on iTunes under the title "Polishing Your Interface Rotations". It covers many different methods on handling interface orientation and is really worth watching. :)
Hope this also helps!