Transitioning UIViews - ios

I am using Facebook SDK in my game in order to post some scores on Facebook.
My code is using the Cocos2D framework so I had to add some code to enable the use of UIView.
Everything works fine except that the view appears in portrait orientation despite the fact that my nibs attributes indicate landscape, the ShouldautoRotate method returns landscape, and the app orientation is also the to landscape.
here is the code that set up the view:
// share to facebook methods
-(void)shareFacebookSelected
{
[[SimpleAudioEngine sharedEngine]stopBackgroundMusic];
[[CCDirector sharedDirector] pause];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
myViewController1 = [[HFViewController alloc] initWithNibName:#"HFViewController_iPhone" bundle:nil];
} else {
myViewController1 = [[HFViewController alloc] initWithNibName:#"HFViewController_iPad" bundle:nil];
}
UIWindow* window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:window cache:YES];
[[[CCDirector sharedDirector]view] removeFromSuperview];
myViewController1.view.hidden = false;
[window addSubview:myViewController1.view];
[UIView commitAnimations];
}
I also enabled a button to return to the normal cocos game and remove the UIView but upon return even my main game orientation has changed to portrait.
any ideas???

The following lines solved my problem:
#define DegreesToRadians(x) ((x) * M_PI / 180.0)
CGRect screenRect = [[UIScreen mainScreen]bounds];
myViewController1.view.transform = CGAffineTransformMakeRotation(DegreesToRadians(90));
myViewController1.view.hidden = false;
myViewController1.view.frame = screenRect;
I basically rotated the view 90 degrees, not the most elegant solution, just brute force but it works. I would still like to understand why it renders the way it does, oh well

Related

how to animate first in a viewWillTransitionToSize using animateAlongsideTransition

I am trying to update my willAnimateRotationToInterfaceOrientation code to use the new viewWillTransitionToSize as a part of IOS 9.
In my app, I have two totally separate views for landscape and portrait (they are laid out differently, in a different pattern).
During rotation the self.view of the viewcontroller is assigned to the correct view (landscape or portrait). In IOS 9 using viewWillTransitionToSize, this revealed a timing race condition between the rotation animation and the assignment of the self.view.
The assignment of self.view = portraitView or self.view = landscapeView could happen either before the rotation, or after the rotation. It appears that because a view assignment is not an "animatable" property that it is executed at any time during the animateWithDuration window.
How do I force the view assignment to happen before the rotation animation?
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
UIInterfaceOrientation oldOrientation = [[UIApplication sharedApplication] statusBarOrientation];
UIInterfaceOrientation orientation = [Utilities orientationByTransforming:[coordinator targetTransform] fromOrientation:oldOrientation];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
[UIView animateWithDuration:[context transitionDuration] animations:^{
if (UIInterfaceOrientationIsLandscape(orientation)) {
self.view = self.landscapeView;
}
else{
self.view = self.portraitView;
}
} completion:^(BOOL finished){
//no completion logic for animateWithDuration
}];
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
//no completion logic for animateAlongsideTransition
}];
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
I think you need to have both views available:
[self.view addSubview: self.landscapeView];
[self.view addSubview: self.portraitView];
And then fade between them
self.landscapeView.alpha = self.portraitView.alpha = 0.0f;
[UIView animateWithDuration:[context transitionDuration] animations:^{
if (UIInterfaceOrientationIsLandscape(orientation)) {
self.landscapeView.alpha = 1.0f;
}
else{
self.portraitView.alpha = 1.0f;
}

iAd Banner won't load correctly

I followed a youtube tutorial on how to implement shared iads banner in my app. I have 10 VC so this is why i choosed the shared iads via delegate. Whenever I launch the app (On device or simulator) the ad doesn't appear on the first view controller. If i switch to the 2nd VC, it will load and show correctly. Then if i decide to go to the 3rd VC or back to the 1st VC, the banner will be white and no ads will load (even if i wait or go to any other VC).
Maybe the tutorial i watched wasn't correctly written, i don't know to be honest. Here's the code used:
AppDelegate.h
#property (strong, nonatomic) ADBannerView *UIiAD;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_UIiAD = [[ADBannerView alloc] init];
return YES;
}
ViewController.h
#property (strong, nonatomic) ADBannerView *UIiAD;
ViewController.m
- (AppDelegate *) appdelegate {
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
-(void) viewWillAppear:(BOOL)animated{
_UIiAD = [[self appdelegate] UIiAD];
_UIiAD.delegate = self;
if ((int)[[UIScreen mainScreen] bounds].size.height == 568)
{
[_UIiAD setFrame:CGRectMake(0,518,320,50)];
}
if ((int)[[UIScreen mainScreen] bounds].size.height == 480)
{
[_UIiAD setFrame:CGRectMake(0,430,320,50)];
}
if ((int)[[UIScreen mainScreen] bounds].size.height == 667)
{
[_UIiAD setFrame:CGRectMake(0,600,320,50)];
}
if ((int)[[UIScreen mainScreen] bounds].size.height == 736)
{
[_UIiAD setFrame:CGRectMake(0,660,320,50)];
}
[self.view addSubview:_UIiAD];
}
-(void) viewWillDisappear:(BOOL)animated{
[_UIiAD removeFromSuperview];
_UIiAD.delegate = nil;
_UIiAD = nil;
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner{
NSLog(#"ads loaded");
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0];
[_UIiAD setAlpha:1];
[UIView commitAnimations];
self.fullscreen = [[RevMobAds session] fullscreen];
self.fullscreen.delegate = self;
[self.fullscreen loadAd];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{
NSLog(#"ads not loaded");
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0];
[_UIiAD setAlpha:0];
[UIView commitAnimations];
}
Conclusion
I tried adding a delay in the ViewWillAppear method but it did not work.
I placed the banner in the storyboard and made sure it was on 0 alpha.
No other answer on SO helped me so hopefully someone will be able to resolve this issue. Thanks!
To conclude my comments,
use storyboard auto layout to position the banner or use a placeholder to get the position of the later banner.
Remove the animations and replace them with .hidden=true and =false.
Set the adBanner to hidden in storyboard or at the point of your initialization.

IOS: View Translation Animation. Proper way.

I'm implementing my own Navigation Controller and I'm faking the animation of adding the new view as in UINavigationContoller.
The following code works great, however if I move -addSubview:, before UIView animation call, it will animate in ios7, but not in ios6, the question is why? (I mean, why does it would make a difference, as animation will be scheduled and executed asynch, right? Or I might suppose It will somehow affect the starting state of animation?)
- (void)didAddViewControllerInNavigationStack:(NSArray*)navigationStack
{
if (self.activeViewController) {
[self.activeViewController viewWillDisappear:YES];
[self.activeViewController viewDidDisappear:YES];
}
self.activeViewController = navigationStack.firstObject;
if (!self.activeViewController) return;
CGRect windowRect = [[UIScreen mainScreen] bounds];
windowRect.origin.x = windowRect.size.width;
self.activeViewController.view.frame = windowRect;
[self.activeViewController viewWillAppear:YES];
[UIView transitionWithView:self.view
duration:0.32
options:UIViewAnimationOptionCurveEaseOut
animations:^ { self.activeViewController.view.frame = [[UIScreen mainScreen] bounds]; }
completion:^(BOOL isDone){[self.activeViewController viewDidAppear:YES];}];
[self.view addSubview:self.activeViewController.view];
[UIView commitAnimations];
}
From the documentation of transitionWithView:duration:options:animations:completion:, it is said you should add the subview inside the animation block:
The block you specify in the animations parameter contains whatever state changes you want to make. You can use this block to add, remove, show, or hide subviews of the specified view.
Also, you are calling commitAnimations without having called beginAnimations:context:. You are mixing things here. Block-based animation API does not need the begin-end API.
Your code should be:
[UIView transitionWithView:self.view
duration:0.32
options:UIViewAnimationOptionCurveEaseOut
animations:^ { [self.view addSubview:self.activeViewController.view]; self.activeViewController.view.frame = [[UIScreen mainScreen] bounds]; }
completion:^(BOOL isDone){[self.activeViewController viewDidAppear:YES];}];

changing UIWebView frame on device rotation

I'm developing an app that is locked to portrait mode. However one view is acting as a full screen 'player' for various media types.
I'm using a UIView subclass that has a UIWebview subview to play the media.
This is presented full screen on top of the viewing stack. My problem arises in making only this view rotate for landscape content - e.g. videos & pdfs.
To do the rotation I'm setting an observer in the init method:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(deviceRotated:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
and rotating as so:
- (void)deviceRotated:(NSNotification *)notification {
UIDeviceOrientation orientation = [[notification object] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft) {
[UIView animateWithDuration:0.6f delay:0.0 options:UIViewAnimationCurveEaseInOut
animations:^{ [self.webView setTransform:CGAffineTransformMakeRotation(M_PI / 2.0)]; }
completion:nil];
}
else if (orientation == UIDeviceOrientationLandscapeRight) {
[UIView animateWithDuration:0.6f delay:0.0 options:UIViewAnimationCurveEaseInOut
animations:^{ [self.webView setTransform:CGAffineTransformMakeRotation(M_PI / -2.0)]; }
completion:nil];
}
else if (orientation == UIDeviceOrientationPortraitUpsideDown) {
[UIView animateWithDuration:0.6f delay:0.0 options:UIViewAnimationCurveEaseInOut
animations:^{ [self.webView setTransform:CGAffineTransformMakeRotation(M_PI)]; }
completion:nil];
}
else if (orientation == UIDeviceOrientationPortrait) {
[UIView animateWithDuration:0.6f delay:0.0 options:UIViewAnimationCurveEaseInOut
animations:^{ [self.webView setTransform:CGAffineTransformMakeRotation(0.0)]; }
completion:nil];
}
}
I know I need to alter the frame size for self.webView when rotating, but I am getting strange results.
I've tried setting to container view as a large 'square' with length [[UIScreen mainscreen] bounds].size.height and placing the web view in the middle, but it moves about inconsistantly - it seems as if the width & height values are getting set from the dimensons before the rotation.
I've also tried setting autoResizingMask flexible height & width, but as the container view is off the screen this stretches the web view offscreen also.

wrong orientation on UIViewController while animating it

In order to use a UISplitViewController, I'm replacing my window root controller when navigating from one view controller to the other.
In order to have some nice transition while doing so, I'm using a zooming effect like this:
MyOtherViewController *controller = [[MyOtherViewController alloc] initWithNibName:#"MyOtherView" bundle:nil];
UIWindow *window = ((MyAppDelegate *)[[UIApplication sharedApplication] delegate]).window;
controller.view.frame = [window frame];
controller.view.transform = CGAffineTransformMakeScale(0.01,0.01);
controller.view.alpha = 0;
[window addSubview:controller.view];
[UIView animateWithDuration:0.2 animations:^{
controller.view.transform = CGAffineTransformMakeScale(1,1);
controller.view.alpha = 1.0;
} completion:^(BOOL finished) {
if (finished) {
[self.view removeFromSuperview];
window.rootViewController = controller;
}
}];
and this works pretty well, except that while doing the animation, the new view is always oriented as if in portrait mode, regardless of the current device orientation. When the animation is finished, the view orients itself correctly.
What am I missing?
Things I've tried:
putting my new controller view as the sole subview of the UIWindow
making my new controller the root view controller before the animation begins
A curious thing is that, if I do a recursiveDescription on the window at the beginning of my method, the window frame is defined as having a size of 768x1024 (i.e., portrait), and the view inside it of 748x1024 but with a transform of [0, -1, 1, 0, 0, 0] (does this mean a rotation or what? Shouldn't it be the identity transform?)
UIWindow doesn't rotate. It has a rotated view inside of it (as you've seen). In this case, though, I think the problem is likely that your view has a transform on it already at this point, and you need to concatenate with it rather than replace it as you're doing in your setTransform: calls.
You shouldn't be asking the app delegate for the window, you should be getting the window from the view (self.view.window).
If at any point you're attaching your view to the window itself, rather than putting it inside the rotation view, then you'll need to know the effective transform of the view you want to match by walking the hierarchy:
- (CGAffineTransform)effectiveTransform {
CGAffineTransform transform = [self transform];
UIView *view = [self superview];
while (view) {
transform = CGAffineTransformConcat(transform, [view transform]);
view = [view superview];
}
return transform;
}
I finally figured out what was wrong. Since the frame is not a real property but a sort of calculated one, based on the values of the view bounds and the view transform, I needed to set the frame after setting the same transform as the current view, and before setting the transform again to set up the initial state of the animation. Also, the frame I need to set is the same one as the current view is currently using, as it is taking into account the window orientation (or lack thereof, as Rob Napier pointed)
So, without further ado, here's the working code:
MyOtherViewController *controller = [[MyOtherViewController alloc] initWithNibName:#"MyOtherView" bundle:nil];
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
CGAffineTransform t = self.view.transform;
controller.view.transform = t;
controller.view.frame = self.view.frame;
controller.view.transform = CGAffineTransformScale(t,.01,.01);;
[window addSubview:controller.view];
controller.view.alpha = 0;
[UIView animateWithDuration:0.2 animations:^{
controller.view.transform = t;
controller.view.alpha = 1.0;
} completion:^(BOOL finished) {
if (finished) {
[self.view removeFromSuperview];
window.rootViewController = controller;
[controller release];
}
}];

Resources