Does anyone know if it is possible to stop an autorotation once a shake gesture is recognized (i.e. don't autorotate during an aggressive shake)?
Autorotation is handled with some quirky low-level stuff which seems to change significantly betweeen major OS releases; I really wouldn't mess with it.
"Cancelling" doesn't really work either — in CoreAnimation speak, the animation has already happened in the "model tree" and the "presentation tree" and "render tree" are catching up. If you've saved the old orientation (i.e. on a rotation, save the old orientation and the time, and compare times) you can call [[UIDevice currentDevice] setOrientation:orientation] but Apple will reject your app.
If the rotation hasn't happened yet, then set a flag at the start of the shake and clear it at the end, and then override -shouldAutorotateForInterfaceOrientation: to return NO if a shake is currently happening.
Register your controller to check if a shake occurs by observing the device orientation, and set a flag in your controller for knowing that shake is currently happening (you could use the date). Then, override shouldAutorotateForInterfaceOrientation method to check the flag and avoid rotation in case the shake is happening now.
Related
I am trying to write an App for Apple tv4 (tvos). When my App starts, the view controller does receive touchesBegan events, as it should.
Without going into too many details, the App creates, moves, and deletes sub-views to respond to the user's interactions.
After a while, the view controller does not receive touchesBegan any more (this is the strange error that I am trying to debug).
Since I think the problem has something to do with the responder chain, I have made the following two experiments:
If I let the view controller override and return true from canBecomeFirstResponder, then the problem still occurs, but it occurs much less frequently.
If I do not override that function and instead check who is the first respnder, then I find that the App has no first responder, even before the strange error occurs. That is to say, the App has no first responder even when it is working properly!
Questions: What can prevent touchesBegan from being invoked? Is it related to the responder change? If so, please explain 2 above.
How exactly are you supposed to "touch" a view rendered on a non-touch screen enabled TV?
You're not.. tvOS doesn't work like iOS in the way that you cannot detect touches because there is no touch screen enabled input device supported on an Apple TV.
Instead, you use the UIFocusEngine to handle interactions with content presented within your view hierarchy.
Check out "Controlling the User Interface with the Apple TV Remote" from Apple's Developer Library for more information.
I'm having real problems with my apps under iOS8. I've made a bunch of OpenGL based apps, which don't need the iOS to handle the orientation. It's all handled within the OpenGL section. But I do use setStatusBarOrientation to make sure any dialogs/keyboards etc that pop up line up with everything else. I'm creating my window and view programatically or in a xib, I've never needed to use a storyboard (in case thats relevant?)
It's all been perfect, til iOS 8 came along.
Now it seems that setStatusBarOrientation isn't behaving properly at all. It's either not changing anything, or it's rotating "something" that stops touches being recorded on half the screen. It's as if the window is being rotated within itself, but visually nothing changes, just the touches are effected.
It's hard to explain, and makes no sense.
But my question is: How do you set the status bar orientation in iOS8? And how do you do it without destroying everything else that works in previous iOS versions?
Set iOS7.1 as your Base SDK, and it'll work fine on iOS8, without all these strange bugs.
http://objcsharp.wordpress.com/2014/09/21/how-to-get-back-the-ios-7-sdk-after-upgrading-to-xcode-6/
found this
if ([UIViewController class]) // iOS8 has this class only
{
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:#"orientation"];
}
found here:
http://blog.lessfun.com/blog/2014/09/24/ios8-issue-keyboard-orientation-and-idletimerdisabled-not-working/
seems to work
I've created a custom view that resizes CALayers in when a pan gesture is triggered. When the control is added to a normal UIVIew, the animation behaves exactly as expected.
When the view is added to a UITableViewCell via addSubViewthe animation is jumpy. I placed some NSLog statements in the gesture handler, and it's behaving exactly as expected.
Is there anything about UITableView or UITableViewCell that would cause this unexpected behavior I am experiencing? Is it even correct to add custom view by using addSubView?
EDIT
I have a little more information on the problem. The issue only seems to be appearing on certain environments.
*iPhone 3GS, iOS 4.2.1 - YES
iPod Touch (Retnia), 5.1 - NO
iPod Simulator 4.2 - NO
iPod Simulator 5.1 - NO
I've also put into place the suggestions from Lorean and DavidH, which didn't solve the issue.
*When I build from XCode, there is a message next to the 3gs device that says "Overriding base SDK to 4.3"
Could this be a potential problem?
You should only add custom views to the cell's content view.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewCell_Class/Reference/Reference.html
While I agree the view should be placed as a subview in the contentView, there is another potential issue. Animations inside moving scrollViews are historically terrible, as the overall system is not designed to support two uncoupled animations.
The solution for that issue is when a user touches the cell, you disable scrolling (ie myTableView.scrollEnabled = NO, then when the pan gesture completes (all animations), enable it again.
EDIT: This is going to sound a bit funky, but should work as I've done similar in the past. When you get the first touch event, calculate what the frame of the layer is self.view coordinates, and then add it to the view using this frame, but saving the old frame. User sees nothing and now your view is on tip. Obviously you must also prevent the table from moving. When you are done with user interactions, then move the view back to the cell using its old frame.
Depending on how you are doing touches, you may need to intercept the first touch in a clear UIView that overlays the desired panning view, and when it gets touched, do all the above, then forward the initial touch to the view. Hopefully this step is not needed.
I've implemented a hack which solves the problem. I may decide to turn off the animation altogether as it's not really needed, but if anyone has a better answer than this I will gladly accept.
if ([[[UIDevice currentDevice] systemVersion] floatValue]<5.0)
{
[CATransaction begin];
[CATransaction setDisableActions: YES];
}
//do stuff
if ([[[UIDevice currentDevice] systemVersion] floatValue]<5.0) [CATransaction commit];
When the app I'm working on is installed either via Ad-Hoc thru iTunes or built directly to the device, upon launching for the first time, the only view controller in my app that responds to orientation changes doesn't receive calls to shouldAutorotateToInterfaceOrientation: with a landscape argument passed in; debugging shows that it's only being called for portrait. Every subsequent launch behaves as I would expect - that is, there are calls to shouldAutorotateToInterfaceOrientation: made both with landscape and portrait arguments. This exact behavior can be seen in the iPhone simulator, on the iPhone and on the iPod touch.
So my question is: why would orientation notifications be different for the first launch of an app than they would be for every subsequent launch? Am I mistaken in believing that I have no control over orientation changes beyond responding to shouldAutorotateToInterfaceOrientation:?
Inside the ViewController in question:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
and inside of viewDidLoad and viewDidUnload I've got (respectively):
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
and
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
Update July 6, 2010:
Still no luck solving the problem. I dropped the issue for a little while and came back to it and am still seeing the problem under completely different circumstances. Anyone?
Update July 13, 2010:
From Apple's View Controller Programming Guide:
"...the window object does much of the work associated with changing the current orientation. [...] Specifically, it works with the view controller whose root view was most recently added to, or presented in, the window. In other words, the window object works only with the frontmost view controller whose view was displayed..."
I'm adding the root view controller to the window differently on the first launch compared to every subsequent launch, so I thought maybe it had something to do with this. I have yet to trace anything back to here though...just a thought.
This thing has had around 175 views at the time of this update...no one has even the most far out obscure suggestion? Come on, throw something out there. I'm willing to entertain any guesses or suggestions at this point. I don't care if it's stupidly obscure or potentially irrelevant.
Never did solve this problem - I left the company where I encountered it before I had a chance to. However, I had a pretty good lead on it by the time I left. I contacted Apple DTS about the issue and they noted that for autorotation to work properly, all ViewControllers in the view stack related to autorotation must call the super methods in the method implementations (i.e. calling [super viewDidLoad] from within the ViewController's viewDidLoad). I don't remember which methods they cited exactly, but it's probably worth a shot to ensure you're properly calling super where appropriate.
[EDIT] If someone can confirm this, I'll mark it as the accepted answer. Thanks!
also make sure you set:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return YES;}
in ALL ViewControllers.m in your app, not just one you're working on (if you have more than one). I was struggling trying to get it going for the FirstViewController, but it wouldn't work no matter what. As soon as I added the above code to all four view controllers, it started to work just fine (in all four)
I had a similar problem - the UIDevice.h header lists endGeneratingDeviceOrientationNotifications and beginGeneratingDeviceOrientationNotifications as "nestable." It turns out I had unbalanced calls to these methods.
I solved this quickly with the following change to beginGeneratingDeviceOrientationNotifications:
if (![[UIDevice currentDevice] isGeneratingDeviceOrientationNotifications])
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
What are single-state and two-stage animation for rotating an iPhone window?
This is the "error" message I get in the Debugger Console (nothing crashes):
Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations.
I was working through the book "Beginning iPhone Development: Exploring the iPhone SDK" by Apress (Dave Mark, Jeff LaMarche) on the Swap Project.
Everything is explained in the UIViewController Class Reference. Especially check out the View Rotation section near the top.
From the reference:
Handling View Rotations
By default, the UIViewController class
displays views in portrait mode only.
To support additional orientations,
you must override the
shouldAutorotateToInterfaceOrientation:
method and return YES for any
orientations your subclass supports.
If the autoresizing properties of your
views are configured correctly, that
may be all you have to do. However,
the UIViewController class provides
additional hooks for you to implement
additional behaviors as needed.
To temporarily turn off features that
are not needed or might otherwise
cause problems during the orientation
change, you can override the
willRotateToInterfaceOrientation:duration:
method and perform the needed actions
there. You can then override the
didRotateFromInterfaceOrientation:
method and use it to reenable those
features once the orientation change
is complete.
If you want to perform custom
animations during an orientation
change, you can do so in one of two
ways. Orientation changes used to
occur in two steps, with notifications
occurring at the beginning, middle,
and end points of the rotation.
However, in iPhone OS 3.0, support was
added for performing orientation
changes in one step. Using a one-step
orientation change tends to be faster
than the older two-step process and is
generally recommended for any new
code.
To add animations for a one-step
orientation change, override the
willAnimateRotationToInterfaceOrientation:duration:
method and perform your animations
there. To use the older two-step
method, override one or both of the
willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
and
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
methods to configure your animations
before each step. You must choose only
one technique and override just the
methods associated with that
technique. If you override either
method associated with the two-step
technique, the view controller uses
that technique by default.
I have found the culprit in my case to be the UIImagePickerController (I also do not override any rotation animation):
[self presentModalViewController:imagePicker animated:YES];
Replacing imagePicker with a generic UIViewController doesn't generate any warnings.
I changed from willAnimateFirstHalfOfRotationToInterfaceOrientation:duration: method to willAnimateRotationToInterfaceOrientation:duration: method and warning gone.
Thanks.
Ed Marty's answer is the correct one. The reason it will happen if you are not overriding any of the rotation animation is probably that you reply "YES" to shouldAutorotate.. for some view. If you do not implement rotation at all, then you should just not override the shouldAutorotate.. method. If you do override that method, then just override the single step rotation method as well and pass it along to the super.
If you're using iOS 4 and you're getting this warning, I found a way to get rid of it. In your info.plist, there is an item called "Supported interface orientations." Select which orientations your application supports and two-stage warnings will go away when bringing up the imagePicker.
#plumiscles answer didn't quite work for me - there was no item called 'Supported Interface Orientations', probably b/c it is an old project. But you can get the same effect by editing the .plist file directly and adding this:
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationPortrait</string>
Need to add UIImagePickerController as a subview to solve this error
[self.view addSubview:picker.view];
[self presentModalViewController:picker animated:NO];
I've had this issue after creating a tabbarcontroller with no view controllers inside (no tabs), this warning disappeared once I attached at least one view controller to it.
I wasn't over riding any of those two-step functions, but I was calling my own function when I received orientationChanged notifications, and I had this line of code in it. Commenting it out got rid of the warning and allowed the auto rotate to work properly. Auto rotate still worked with this line of code until iOS 4.2, then it broke completely. Spent a lot of time looking for why the built in autoRotate stopped working in 4.2. Maybe this will help someone else.
Commented out this line to make it work:
[[UIApplication sharedApplication] setStatusBarOrientation:currentOrientation animated:YES];
I've delete from plist "Supported interface orientations" row and warning disappears.
I just had the same problem. In my case was a silly mistake that I'm putting here just in case anyone else falls into that same issue.
In my tabbed app I remove one of the original ViewControllers and added a new one with Storyboard to create a "Settings" section.
This new VC had to be a table view VC and even I designed, compiled and run it without a problem, when I changed the orientation of the app I kept getting this “Using two-stage rotation animation” error.
My problem was that I forgot to change in the original .h file interface "UIViewController" for "UITableViewController".
Once this was done I changed on the Storyboard identity badge the class from the general value to my SettingsViewController and that was the end of it.
I hope it can help someone else. It took me a while to get to bottom of this.
Cheers,