I've created a custom UIAlertView (by subclassing it and messing around with its show function) that has some custom subviews and is of non-standard size.
It works ok when I create and display it, however, when the device is rotated, the alert rotates and then returns to its default size.
Any ideas what functions to override - or should I tweak the UIViewController?
thanks,
Peter
Not sure if force rotating the UIAlertView fits the Apple GUI guidelines, but you can rotate it by defining the status bar (status bar and UIAlertView sticks together)
application.statusBarOrientation = UIInterfaceOrientationLandscapeRight;
application.statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
But UIAlertView is a UIView just like many others, so try this :
- (void)didPresentAlertView:(UIAlertView *)alertView
{
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.1];
alertView.transform = CGAffineTransformRotate(alertView.transform, degreesToRadian(90));
[UIView commitAnimations];
}
Related
My tableview has 4 cells, and each cells has one different picture as background.
When I rotate the iPhone, the height of the rows change, and also the pictures.
Is really easy to change picture if the position is in landscape or in portrait, but the picture change when the iPhone is already rotated, not while is rotating!
What's the problem?
For example: the iPhone is in portrait and the user rotates it in landscape.
That there is a very ugly effect, because the pictures change just when the iPhone is in landscape, and for a fraction of a second the user sees the portrait picture deformed (before that it changes).
How can I solve it?
Thanks
The easy way:
Implement willAnimateRotationToInterfaceOrientation in your view controller. Inside this method you can reorient your pictures and they'll automatically be animated. There's a short overview this and other available interface orientation methods at http://www.dizzey.com/development/ios/handling-layout-on-uiinterfaceorientation-change/
Pointlessly difficult way:
You could manually track acceleration and write your own animation blocks.
Set your view controller as a UIAccelerometerDelegate. Reference the sharedAccelerometer as follows.
accel = [UIAccelerometer sharedAccelerometer];
accel.delegate = self;
accel.updateInterval = 1.0f/60.0f;
Then implement this delegate method. This will be run every time the accelerometer notices acceleration. Tracking acceleration in the X axis will give you landscape/portrait orientation.
#pragma mark UIAccelerometer delegate method
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
if(acceleration.x > 0.8) //landscape right
{
[UIView beginAnimations:#"text spin" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.2];
//do some animation to landscape right
[UIView commitAnimations];
}
if(acceleration.x < -0.8) //landscape left
{
[UIView beginAnimations:#"text spin" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.2];
//do some animation to landscape left
[UIView commitAnimations];
}
if(acceleration.x < 0.2 && acceleration.x > -0.2) //portrait
{
[UIView beginAnimations:#"text spin" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.2];
//do some animation to portrait view
[UIView commitAnimations];
}
In a situation like this, during a rotation I tend to just use the .hidden property on elements (myObject.hidden = YES) and then restore them when the rotation is complete.
I imagine your picture frames have more room in landscape view - another suggestion if this is true, is to keep them the same size in both orientations, then you wouldn't need to hide them during a rotation, for example.
Hope this helps!
I'm having a problem with FBDialog.
Apparently after the either the email or the password textFields become first responders and keyboard comes up, the FBDialog view no longer reacts to changing the interface orientation.
Except for the case when keyboard is up, all works as expected.
Did anyone ever encounter this behavior?
Thanks in advance, Vlad
Try this:
(void)deviceOrientationDidChange:(void*)object
{
UIDeviceOrientation orientation = (UIDeviceOrientation)[UIApplication sharedApplication].statusBarOrientation;
if ([self shouldRotateToOrientation:orientation])
{
[self updateWebOrientation];
CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
[self sizeToFitOrientation:YES];
[UIView commitAnimations];
}
}
I have an iAd which displays at the top of a fullscreen subview of the main view. The iAd works normally in portrait mode, and I have handled rotation of the iAd banner view into landscape mode. The issue occurs when the iAd is tapped by the user in landscape mode. The test advertisement displays in portrait, sideways on the phone, and when the user taps the x to dismiss the iAd, the banner view and its parent view are pushed offscreen. The iAd behaves normally in portrait mode (i.e. tapping it and closing it results in the view containing the banner to be displayed normally).
Things I have tried:
- (void)bannerViewActionDidFinish:(ADBannerView *)banner{
NSLog(#"Ad was closed, show the adView again");
if(UIInterfaceOrientationIsLandscape(currentInterfaceOrientation)){
[self animateRotationToLandscape:0.3f];
}
else{
[self animateRotationToPortrait:0.3f];
}
}
-(void)animateRotationToPortrait:(NSTimeInterval)duration{
self.adView.currentContentSizeIdentifier =
ADBannerContentSizeIdentifierPortrait;
BOOL iPad = NO;
#ifdef UI_USER_INTERFACE_IDIOM
iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
#endif
if (iPad) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
proUpgradeDescription.frame = CGRectMake(82,313,604,110);
proUpgradePrice.frame = CGRectMake(313,576,142,28);
closeButton.frame = CGRectMake(348,834,72,37);
purchaseButton.frame = CGRectMake(313,431,142,142);
[UIView commitAnimations];
}
else{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
proUpgradeDescription.frame = CGRectMake(20,80,280,70);
proUpgradePrice.frame = CGRectMake(88,322,142,28);
closeButton.frame = CGRectMake(123,403,72,37);
purchaseButton.frame = CGRectMake(88,172,142,142);
[UIView commitAnimations];
}
}
Which calls code that I use to animate rotation of the display for portrait and landscape mode. This code has no effect.
If anyone has any ideas as to why the test advertisements don't rotate correctly and why they push the parent view controller off the screen I would greatly appreciate it.
I don't know if this addresses all of your problems, but according to the answer on this question, the test ads are only in portrait, and real ads will show up in both orientations.
I know the question is a little old so I'm posting here just in case someone runs into the same problem (I did).
ADBannerView messes with the frame and transform properties of the parent view so all you have to do is to reset them to their original values after it has finished (in bannerViewActionDidFinish:).
I still don't understand why it doesn't put back everything the way it was after it has finished. We shouldn't have to do this.
This drove me nuts too. Delivering only landscape full page ads to the iPad and portrait to the iPhone and not saying so is asking for trouble. I gave up using the iAdSuite code, which caused the Landscape iPad ad to leave the screen in Landscape even when the device was in portrait!
This is my code for banner ads. It is all in the first view controller loaded. It aims to put the banner at the bottom of the screen.
In the header file:
#import "iAd/ADBannerView.h"
#property (strong, nonatomic) ADBannerView* adView;
#interface myViewController : UIViewController <ADBannerViewDelegate,
in viewDidLoad
CGRect contentFrame = self.view.bounds;
CGRect bannerFrame = CGRectZero;
bannerFrame.size = [adView sizeThatFits:contentFrame.size];
bannerFrame.origin.y = contentFrame.size.height-bannerFrame.size.height;
adView = [[ADBannerView alloc] initWithFrame:bannerFrame];
[adView setDelegate:self];
[self.view addSubview:adView];
Then
-(void)viewWillLayoutSubviews {
CGRect contentFrame = self.view.bounds;
CGRect bannerFrame=CGRectZero;
bannerFrame.size = [adView sizeThatFits:contentFrame.size];
if (adView.bannerLoaded) {bannerFrame.origin.y = contentFrame.size.height-bannerFrame.size.height;}
else {bannerFrame.origin.y = contentFrame.size.height;}
[adView setFrame:bannerFrame];}
Then to handle the callbacks from iAd we need to tell the view to redo its layout if something changes:
- (void)bannerViewDidLoadAd:(ADBannerView *)banner{
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];}
This seems to handle the orientation correctly on both iPad and iPhone except for the test full page ads. However, the screen assume correct orientation after the test ad is dismissed so I am hoping it is all OK.
How do I change or disable the rotating animation when screen orientation changes from landscape to portrait, or vice versa?
Yes, it is possible to disable the animation, without breaking everything apart.
The following codes will disable the "black box" rotation animation, without messing with other animations or orientation code:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[UIView setAnimationsEnabled:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[UIView setAnimationsEnabled:NO];
/* Your original orientation booleans*/
}
Place it in your UIViewController and all should be well. Same method can be applied to any undesired animation in iOS.
Best of luck with your project.
If you dont want your view controllers to rotate just override the shouldAutoRotateToInterface view controller method to return false for whichever orientation you dont want to support...Here is a reference.
In the case that u just want to handle rotation some other way, you can return false in the above methods and register for UIDeviceOrientationDidChangeNotification like so
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(handleOrientationDidChange:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
Now when u get the notifications u can do whatever you want with it...
The answer by #Nils Munch above is find for < iOS7. For iOS 7 or later you can use:
- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[UIView setAnimationsEnabled:NO];
[coordinator notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
[UIView setAnimationsEnabled:YES];
}];
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
Okay, this is the code:
[lblMessage setText: txtEnter.text];
[lblMessage sizeToFit];
scrollingTextView.contentSize = lblMessage.frame.size;
float width = (lblMessage.frame.size.width) + (480);
[UIView beginAnimations:#"pan" context:nil];
[UIView setAnimationDuration:durationValue];
[UIView setAnimationRepeatCount:5];
scrollingTextView.contentOffset = CGPointMake(width,0);
[UIView commitAnimations];
//The scrolling text view is rotated.
scrollingTextView.transform = CGAffineTransformMakeRotation (3.14/2);
[self.navigationController setNavigationBarHidden:YES];
btnChange.transform = CGAffineTransformMakeRotation (3.14/2);
I have the user enter in some text, press a button and then a label is replaced with the text, turned 90 degrees in a scrollview on a page.
After a certain number of characters, for example say 20.. the animation just won't load. I can go back down until the animation will run.
Any ideas on where I am going wrong, or a better way of storing the text etc etc ?
Core Animation animations are performed on a separate thread. When you enclose the change in contentOffset in a beginAnimations / commitAnimations block, that change will be animated gradually. The scrolling text view rotation that occurs next, outside of the animation block, will be performed instantly. Since both are interacting with the same control on different threads, it's not surprising that you're getting weird behavior.
If you want to animate the rotation of the text in the same way as the contentOffset, move that line of code to within the animation block.
If you want to have the rotation occur after the offset change animation has completed, set up a callback delegate method. You can use code in the beginning of your animation block similar to the following:
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(contentOffsetAnimationHasFinished:finished:context:)];
which requires you to implement a delegate method like the following:
- (void)contentOffsetAnimationHasFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context;
{
// Do what you need to, now that the first animation has completed
}
EDIT (2/6/2009):
I just created a simplified version of your application, using only the sideways text scrolling, and find no problem with the animation on the device with any number of characters. I removed all extraneous calls to layout the buttons, etc., and only animate the text. Rather than apply the rotation transform to the scroll view every time you click the button, I have it start rotated and stay that way.
I thought it might be a layer size issue, as the iPhone has a 1024 x 1024 texture size limit (after which you need to use a CATiledLayer to back your UIView), but I was able to lay out text wider than 1024 pixels and still have this work.
A full Xcode project demonstrating this can be downloaded here. I don't know what your issue is, but it's not with the text animating code you present here.
Right, this code is working fine in the simulator, and works fine until i enter more than say 20 characters in txtEnter.text:
- (IBAction)updateMessage:(id)sender
{
//Animation coding
//Put the message in a resize the label
[lblMessage setText: txtEnter.text];
[lblMessage sizeToFit];
//Resize the scrolliew and change the width.
scrollingTextView.contentSize = lblMessage.frame.size;
float width = (lblMessage.frame.size.width) + (480);
scrollingTextView.transform = CGAffineTransformMakeRotation (3.14/2);
//Begin the animations
[UIView beginAnimations:#"pan" context:nil];
[UIView setAnimationDuration:durationValue];
[UIView setAnimationRepeatCount:5];
//Start the scrolling text view to go across the screen
scrollingTextView.contentOffset = CGPointMake(width,0);
[UIView commitAnimations];
//General hiding and showing points.
[txtEnter resignFirstResponder];
[btnChange setHidden:NO];
[txtEnter setHidden:YES];
[btnUpdate setHidden:YES];
[lblSpeed setHidden:YES];
[lblBackground setHidden:YES];
[backgroundColourControl setHidden:YES];
[speedSlider setHidden:YES];
[scrollingTextView setHidden:NO];
[backgroundImg setHidden:NO];
[toolbar setHidden:YES];
[self.navigationController setNavigationBarHidden:YES animated:YES];
//Depending on the choice from the segment control, different colours are loaded
switch([backgroundColourControl selectedSegmentIndex] + 1)
{
case 1:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
break;
case 2:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:YES];
break;
default: break;
}
btnChange.transform = CGAffineTransformMakeRotation (3.14/2);
}
I've tried your method Brad, but can't seem to get the (void) section to work properly.
What my app does its fill the label with a message and then rotates them all to act like it's in landscape mode. Then what it does it scroll the label within a scrollview to act like a scrolling message across the screen.