I got a problem to integrate iAd in my iPhone apps -- the banner ad is fine when it expends (see http://www.clingmarks.com/iAd1.png and http://www.clingmarks.com/iAd2.png), however, when I close it, it left a white blank screen (see http://www.clingmarks.com/iAd3.png). I couldn't figure out why. Here is how I integrate the ad:
Because I need to support other ads for lower version of iPhone OSes, I add a container view at the top of the apps, whose view controller is AdViewController. When the view is loaded, I create a AdBannerView programmatically and add it as a subview to the AdViewController.view. Here is the code in the viewDidLoad method:
Class adClass = (NSClassFromString(#"ADBannerView"));
if (adClass != nil) {
iAdView = [[ADBannerView alloc] initWithFrame:CGRectZero];
iAdView.frame = CGRectOffset(iAdView.frame, 0, -50);
iAdView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifier320x50];
iAdView.currentContentSizeIdentifier = ADBannerContentSizeIdentifier320x50;
iAdView.delegate = self;
iadViewIsVisible = NO;
[self.view addSubview:iAdView];
} else {
// init google adsense
}
Following are the delegate methods:
enter code here
- (void)bannerViewDidLoadAd:(ADBannerView *)banner {
if (!iadViewIsVisible) {
[UIView beginAnimations:#"animateAdBannerOn" context:NULL];
// banner is invisible now and moved out of the screen on 50 px
banner.frame = CGRectOffset(banner.frame, 0, 50);
[UIView commitAnimations];
iadViewIsVisible = YES;
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
if (iadViewIsVisible) {
[UIView beginAnimations:#"animateAdBannerOff" context:NULL];
// banner is visible and we move it out of the screen, due to connection issue
banner.frame = CGRectOffset(banner.frame, 0, -50);
[UIView commitAnimations];
iadViewIsVisible = NO;
}
}
Eventually I figured it out myself. It turns out the ADBannerView's parent view must be a fullscreen view. I my case above, I added AdBannerView to my adView, which is a view with size 320x50. When I changed its parent view to a fullscreen view, everything works. I am not sure if this is a bug in iAd, but certainly something tricky.
When the banner finishes, it moves itself to the top of the screen even if that means having a negative y coordinate. I center the banner when it finishes. In my case there is a view controller for just the banner, so it is only full screen when the ad is clicked.
-(void) bannerViewActionDidFinish:(UIView *)inBanner {
CGRect frame = [inBanner frame];
frame.origin.x = frame.size.width * 0.5;
frame.origin.y = frame.size.height * 0.5;
[inBanner setCenter:frame.origin];
}
Hey David! I know what you mean, I'm also using an own AdvertisementViewController which calls different ad networks.
So iAd is not in a full screen view but inside a 320x50 view.
Simply do this:
-(void) bannerViewActionDidFinish:(ADBannerView *)inBanner {
[self.view setFrame:CGRectMake(0.0f, 0.0f, 320.0f, 50.0f)];
}
So the outer view container (self.view) is resized to its original size. iAd is resizing it to fullscreen for displaying the ad when an iAd is shown.
Related
I am using the EGORefreshTableHeaderView [1] to fetch new data from a server into a UITableView.
This works pretty good but in iOS 5.1 the EGORefreshTableHeaderView does not scroll back into the intended height when the user releases the pull down. Normally it should scroll back to an contentInset of 60px. Then the loading view should be visible for the time which the loading process takes and after that scroll back to 0px inset.
The first scroll-back should happen in the egoRefreshScrollViewDidEndDragging:scrollView method.
- (void)egoRefreshScrollViewDidEndDragging:(UIScrollView *)scrollView {
BOOL _loading = NO;
if ([_delegate respondsToSelector:#selector(egoRefreshTableHeaderDataSourceIsLoading:)]) {
_loading = [_delegate egoRefreshTableHeaderDataSourceIsLoading:self];
}
if (scrollView.contentOffset.y <= - 65.0f && !_loading) {
if ([_delegate respondsToSelector:#selector(egoRefreshTableHeaderDidTriggerRefresh:)]) {
[_delegate egoRefreshTableHeaderDidTriggerRefresh:self];
}
[self setState:EGOOPullRefreshLoading];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.2];
scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);
[UIView commitAnimations];
//I've also tried it with block animations! But doesn't work!
/*[UIView animateWithDuration:0.2 animations:^{
scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);
}];*/
}
}
The problem is that when a user releases the scroll view on the half of the screen (shown in the screenshot below), the scrollview does not bounce back into the 60px inset where it should reload the data.
My first idea was that it is because of the animations. So I changed it to block animations but nothing changes. I guess the problem is that the animations are not executed on commitAnimations rather at the end of the loading.
Does anyone have a solution for this?
[1]... https://github.com/enormego/EGOTableViewPullRefresh
I would pull up their demo application and follow their delegate methods.
put this inside didEndDragging:
[_delegate egoRefreshScrollViewDidEndDragging:scrollView];
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.
I am switching between views using view animations, its works but I am having an issue with interface orientation.
I have two views on window.
authenticationViewCont
mainViewCont
Both have a button, when button clicked on authenticationViewCont I remove it and show mainViewCont and vice versa.
Once I addSubview the authenticationViewCont.view and putting device in portrait mode then removed it by removeFromSuperview then I change device orientation to landscape in my hands then again addSubview the authenticationViewCont. It first displayed animating in portrait and changing orientation after animation.
-(void)mainToAuthentication {
CGRect originalFrame = authenticationViewCont.view.frame;
CGRect modifiedFrame = originalFrame;
modifiedFrame.origin.y = originalFrame.size.height;
// made view out from screen
authenticationViewCont.view.frame = modifiedFrame;
// add sub view on top of other views
[self.window addSubview:authenticationViewCont.view];
// transiting view from bottom to center of screen
[UIView animateWithDuration:0.5
animations:^{ authenticationViewCont.view.frame = originalFrame; }
completion:^(BOOL finished){ mainViewCont.view removeFromSuperview; }];
}
-(void)authenticationToMain {
CGRect originalFrame = mainViewCont.view.frame;
CGRect modifiedFrame = originalFrame;
modifiedFrame.origin.y = -originalFrame.size.height;
// made view out from screen
mainViewCont.view.frame = modifiedFrame;
// add sub view on top of other views
[self.window addSubview:mainViewCont.view];
// transiting view from top to center of screen
[UIView animateWithDuration:0.5
animations:^{ mainViewCont.view.frame = originalFrame; }
completion:^(BOOL finished){ authenticationViewCont.view removeFromSuperview; }];
}
How can I make it to display in current interface orientation instead of old interface orientation in which it was removeFromSuperview?
I think the problem here is that you are initialliy adding one viewController.view ontop of another then removing the old one.
The problem with window only expects one rootViewController. So the window will only pass rotation events onto the first controller. Meaning your second viewController will not get rotation events until the completionsBlock gets called.
The way I would get around this is to put this switching code inside of a rootViewController that is on the window. Then whenever you do your switching you can pass in the current rotation of the rootviewController and have your authenticationViewController set itself up based on the orientation you pass it
In an iOS 4.2 application, I've programmatically created a window, view controller, UIView and two subviews: an EAGLView and an ADBannerView. My code is a combination of a standard EAGLView and Apple's BasicAdBanner code.
I'm able to see iAd banners, but am not able to "click" on them - on device or in simulator. The view controller implements ADBannerDelegate, and receives bannerViewDidLoadAd etc messages, but does not ever receive a bannerViewActionShouldBegin message.
The behaviour is not changed by replacing the EAGL view with a UITextView or only having the ADBannerView, so I'm assuming that my problem lies with the programmatic creation of the window or view controller. Any help would be appreciated.
In addition, my views don't rotate/resize automatically like the ad banner sample does, but that's a less pressing issue.
Code Follows-
AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create the window programatically:
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// let's enable multitouch and user interaction
window.userInteractionEnabled=YES;
window.multipleTouchEnabled=YES;
window.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
window.autoresizesSubviews = YES;
controller = [GLViewController alloc];
window.rootViewController = controller;
[window addSubview:controller.view];
glView = [controller.glView retain];
[window makeKeyAndVisible];
return YES;
}
ViewController:
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
}
-(void)viewDidLoad
{
[super viewDidLoad];
// I'd like to get device orientation notifications.
//[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
//[[NSNotificationCenter defaultCenter] addObserver:self
// selector:#selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
// the GL VIEW I want.
glView = [[EAGLView alloc] initWithFrame:[UIScreen mainScreen].bounds];
glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
glView.userInteractionEnabled=NO;
[self.view addSubview:glView];
// testing with a textview
//content = [[UITextView alloc] initWithFrame:[UIScreen mainScreen].bounds];
//content.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
//content.userInteractionEnabled=NO;
//[self.view addSubview:content];
if (self.banner==NULL)
[self createADBannerView];
[self layoutForCurrentOrientation:NO];
}
-(void)createADBannerView
{
// --- WARNING ---
// If you are planning on creating banner views at runtime in order to support iOS targets that don't support the iAd framework
// then you will need to modify this method to do runtime checks for the symbols provided by the iAd framework
// and you will need to weaklink iAd.framework in your project's target settings.
// See the iPad Programming Guide, Creating a Universal Application for more information.
// http://developer.apple.com/iphone/library/documentation/general/conceptual/iPadProgrammingGuide/Introduction/Introduction.html
// --- WARNING ---
// Depending on our orientation when this method is called, we set our initial content size.
// If you only support portrait or landscape orientations, then you can remove this check and
// select either ADBannerContentSizeIdentifierPortrait (if portrait only) or ADBannerContentSizeIdentifierLandscape (if landscape only).
NSString *contentSize;
if (&ADBannerContentSizeIdentifierPortrait != nil)
{
contentSize = UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifierLandscape;
}
else
{
// user the older sizes
contentSize = UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
? ADBannerContentSizeIdentifier320x50 : ADBannerContentSizeIdentifier480x32;
}
// Calculate the intial location for the banner.
// We want this banner to be at the bottom of the view controller, but placed
// offscreen to ensure that the user won't see the banner until its ready.
// We'll be informed when we have an ad to show because -bannerViewDidLoadAd: will be called.
CGRect frame;
frame.size = [ADBannerView sizeFromBannerContentSizeIdentifier:contentSize];
frame.origin = CGPointMake(0.0f, 0.0f);//CGRectGetMaxY(self.view.bounds)); // this can't be called until the view exists!
// Now to create and configure the banner view
ADBannerView *bannerView = [[ADBannerView alloc] initWithFrame:frame];
// Set the delegate to self, so that we are notified of ad responses.
bannerView.delegate = self;
bannerView.hidden = YES;
// Set the autoresizing mask so that the banner is pinned to the bottom
bannerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
// Since we support all orientations in this view controller, support portrait and landscape content sizes.
// If you only supported landscape or portrait, you could remove the other from this set.
bannerView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil];
//support for 4.0 and 4.1: //(&ADBannerContentSizeIdentifierPortrait != nil) ?[NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil]:[NSSet setWithObjects:ADBannerContentSizeIdentifier320x50, ADBannerContentSizeIdentifier480x32, nil];
// At this point the ad banner is now be visible and looking for an ad.
self.banner = bannerView;
[self.view addSubview:bannerView];
[bannerView release];
}
-(void)layoutForCurrentOrientation:(BOOL)animated
{
//CGFloat animationDuration = animated ? 0.2f : 0.0f;
// by default content consumes the entire view area
CGRect contentFrame = self.view.bounds;
// the banner still needs to be adjusted further, but this is a reasonable starting point
// the y value will need to be adjusted by the banner height to get the final position
CGPoint bannerOrigin = CGPointMake(CGRectGetMinX(contentFrame), CGRectGetMaxY(contentFrame));
CGFloat bannerHeight = 0.0f;
// First, setup the banner's content size and adjustment based on the current orientation
if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
// if(UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
banner.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;//(&ADBannerContentSizeIdentifierLandscape != nil) ? ADBannerContentSizeIdentifierLandscape : ADBannerContentSizeIdentifier480x32;
else
banner.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;//(&ADBannerContentSizeIdentifierPortrait != nil) ? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifier320x50;
bannerHeight = banner.bounds.size.height;
// Depending on if the banner has been loaded, we adjust the content frame and banner location
// to accomodate the ad being on or off screen.
// This layout is for an ad at the bottom of the view.
if(banner.bannerLoaded)
{
// HMM this is going to be a problem for a GLView..
banner.hidden = NO;
contentFrame.size.height -= bannerHeight;
bannerOrigin.y -= bannerHeight;
NSLog(#"Banner will be %f x %f, content resized to %f x %f\n", banner.frame.size.width,bannerHeight,contentFrame.size.width,contentFrame.size.height);
}
else
{
banner.hidden = YES;
//bannerOrigin.y += bannerHeight;
NSLog(#"Banner will be offscreen, content resized to %f x %f\n", contentFrame.size.width,contentFrame.size.height);
}
//EDIT: contrary to my OP, this UIViewAnimateWithDuration code was not commented out!
// And finally animate the changes, running layout for the content view if required.
[UIView animateWithDuration:animationDuration
animations:^{
glView.frame = contentFrame;
[glView layoutIfNeeded];
banner.frame = CGRectMake(bannerOrigin.x, bannerOrigin.y, banner.frame.size.width, banner.frame.size.height);
}];
}
ADBannerViewDelegate:
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
[self layoutForCurrentOrientation:YES];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(#"Failed to receive and ad: %s %s %s\n",error.localizedFailureReason.UTF8String, error.localizedDescription.UTF8String, error.localizedRecoverySuggestion.UTF8String);
[self layoutForCurrentOrientation:YES];
}
-(BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
// this indicates that the banner has been clicked.. confirm?
NSLog(#"banner clicked: will %s application\n",willLeave?"leave":"cover");
return YES;
}
Just to reiterate what forksandhope said,
Placing the ADView in a UIView, then modifying the frame size of both causes the ADView to become un-clickable.
To get around this, create a super UIView and add your UIView and ADView to this view.
For example:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
// initialize the content UIView and/or UIViewController
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
// copy the content view to a class data member
_contentView = self.view;
// create the super UIView
self.view = [[UIView alloc] initWithFrame:_contentView.frame];
// add the content view to the super view
[self.view addSubview:_contentView];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willBeginBannerViewActionNotification:) name:BannerViewActionWillBegin object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didFinishBannerViewActionNotification:) name:BannerViewActionDidFinish object:nil];
}
return self;
}
Then when an ad is loaded, add the ADView to the super view:
- (void)showBannerView:(ADBannerView *)bannerView animated:(BOOL)animated
{
// ...
// add the AdView to the super view
[self.view addSubview:_adBanner.adBannerView];
// ...
}
Then layout your view as desired
- (void)layoutAnimated:(BOOL)animated
{
// ...
[UIView animateWithDuration:animated ? 0.4 : 0.0 animations:^{
_adBanner.adBannerView.frame = _bannerFrame;
[self.view layoutIfNeeded];
// update the content view AND NOT the super view
_contentView.frame = _contentFrame;
}];
// ...
}
Clarification:
It seems that problem is related to the code attempting to set or animate the content frame changes at the end of -layoutForCorrentOrientation(BOOL). if I only set the banner frame's location, I'm able to click the banner, but if I also attempt to set the glView's frame and recreate the surface, the banner does not respond to input.
//EDIT: contrary to my OP, this UIViewAnimateWithDuration code was not commented out!
// And finally animate the changes, running layout for the content view if required.
//[UIView animateWithDuration:animationDuration
// animations:^{
// glView.frame = contentFrame;
// [glView layoutIfNeeded];
banner.frame = CGRectMake(bannerOrigin.x, bannerOrigin.y, banner.frame.size.width, banner.frame.size.height);
// }];
APENDED:
In the end, the problem was that I have a top level UIView (controller.view) which has the glView and the banner as sub-views. Turns out I needed to call
[self.view setNeedsLayout]
to get this top level view to update its bounds so that it allowed button presses down to the banner! (credit goes to Ephraim's answer to a post on UIButtons not responding after rotations
Heey,
In my iPad application I have a UIPopoverController with a UIViewController containing some textfields.
When the keyboard comes up, the Popover gets animated to fit. Does anybody know how to disable this?
Thanks
I dont think you can except make the popovers smaller in height...Its done like that so when your keyboard pops up none of the popover gets covered by it (thus it shrinks back), however i have found it to be annoying at times since it messed with table views (not making them able to scroll all the way and having to resize them)
It would be great if it did actually animate to better part of the screen, I think you mean it actually shrinks the popUp which is mostly not good.(which i see during rotation in my case). You can not keep the popUp from squishing, UNLESS you move a view. The best way to handle this is to temporarily move your entire main UIView of the whole screen up with the keyBoard by the difference between the size of your pop up, and how much that pop up would shrink if you did not move it up... you can't just move it up by the size of your keyboard, because popUps up high would then also be effected. This code below is for when the keyboard rotated, similar code for when it is first introduced. easy to do, EXCept for when you rotate the screen, then things get tricky...
in otherwords, sometimes your UIView will not move at all, sometimes it will move up by a good 170 points.
//-----------------finding the keyboard top (also used on "didRotate")----very handy,
// took me hours to figure out an absolute always work topOfKeyboard, so here you go.-------
//--------------------------------------------------------------------------------
- (void)keyboardWillShow:(NSNotification*)notification
{
NSLog(#" keyboardWillShow");
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
NSDictionary* info = [notification userInfo];
keyboardRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardRect = [(UIView*)keyWindow convertRect:keyboardRect toView:mainViewController.view];
keyboardIsVisible = TRUE;
topOfKeyboard = keyboardRect.origin.y;
the tricky part is finding the PopUp bottom, because there appears to be code in the popup itself or the convertRect:toView: code that makes the origin flaky , (if you try to "view" origin after a "convertRect:toView:" code), it wants to move and be in different spots during rotation,(or one of it's super views) so bottom calc comes out different some times,(not predicable) because of async process of the rotation of different elements possibly because the popUp itself has many superviews down in the pop up. (to see problem in action with pop up and, must have keyboard effecting popup, move the whole view up then log the "origin" and "size" of popUp after the "convertRect:toView:" code)... the "origin" i'm talking about is the origin of the frame after it is translated to the main view (or atleast a couple views up) with the "convertRect:toView:" code....
update:(it appears if you move down about 3 superviews from the popUp, the flakiness goes away... (this code below was in a "didRotate" ipad type of code. That is that the popUp has several superviews before you can get to the one that is projected ontop of the proper frame
UIPopoverController probably should have a property that has the origin that is predicted after a rotation in it, in a type of "will rotate" kind of code, (because of the keyboard problem), instead of just the "popoverContentSize", (also should include the popoverContentSize that would have been without the keyboard as another variable, ".. anyway This is how I had to do it, see code below.
//--------------------------------------------------------------------------------
- (void) checkRotation
{
NSLog(#" ");
NSLog(#"checkRotation");
if (wasOffset)
{
wasOffset = false;
[UIImageView beginAnimations:nil context:NULL];
[UIImageView setAnimationDuration:0.2f];
CGRect frame = carousel.frame;
frame.origin.y += offset;
carousel.frame = frame;
[UIImageView commitAnimations];
[popPickerController presentPopoverFromRect:zoneButton.frame inView:[zoneButton superview] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
if (popPickerController.popoverVisible)
{
if (keyboardIsVisible)
{
wasOffset = false;
[popPickerController presentPopoverFromRect:zoneButton.frame inView:[zoneButton superview]
permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
upView3 = [[[popPickerController.contentViewController.view superview] superview] superview]; //hey it works... :o)
//NSLog(#" ");
//NSLog(#"upView3.frame.origin.x = %f",upView3.frame.origin.x);
//NSLog(#"upView3.frame.origin.y = %f",upView3.frame.origin.y);
//NSLog(#"upView3.frame.size.height = %f",upView3.frame.size.height);
//NSLog(#"upView3.frame.size.width = %f",upView3.frame.size.width);
//NSLog(#" ");
popUpRect.origin.x = upView3.frame.origin.x;
popUpRect.origin.y = upView3.frame.origin.y;
popUpRect.size.height = popUpSize.height;
popUpRect.size.width = popUpSize.width; //you must save the size because the keyboard destroys it before you can use it. very tricky....
//NSLog(#" ");
//NSLog(#"popUpRect.origin.x = %f",popUpRect.origin.x);
//NSLog(#"popUpRect.origin.y = %f",popUpRect.origin.y);
//NSLog(#"popUpRect.size.height = %f",popUpRect.size.height);
//NSLog(#"popUpRect.size.width = %f",popUpRect.size.width);
//NSLog(#" ");
//NSLog(#" ");
//NSLog(#"keyboardIsVisible = %d", keyboardIsVisible);
//NSLog(#" ");
//NSLog(#"keyboardRect.origin.x = %f",keyboardRect.origin.x);
//NSLog(#"keyboardRect.origin.y = %f",keyboardRect.origin.y);
//NSLog(#"keyboardRect.size.height = %f",keyboardRect.size.height);
//NSLog(#"keyboardRect.size.width = %f",keyboardRect.size.width);
//NSLog(#"topOfKeyboard = %f",topOfKeyboard);
CGFloat bottomOfPicker = popUpRect.origin.y + popUpRect.size.height - amountShadowCanEncroach;
//NSLog(#" ");
//NSLog(#"bottomOfPicker = %f",bottomOfPicker);
//NSLog(#"topOfKeyboard = %f",topOfKeyboard);
//NSLog(#" ");
if (bottomOfPicker > topOfKeyboard)
{
wasOffset = true;
offset = bottomOfPicker - topOfKeyboard;
NSLog(#"offset = %f",offset);
[UIImageView beginAnimations:nil context:NULL];
[UIImageView setAnimationDuration:0.2f];
CGRect frame = carousel.frame;
frame.origin.y -= offset;
carousel.frame = frame;
[UIImageView commitAnimations];
}
}
[popPickerController presentPopoverFromRect:zoneButton.frame inView:[zoneButton superview] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
and moving the main UIView back
//-----------------------------------------------------------------------------
- (void) searchDidEndEditing
{
NSLog(#"searchDidEndEditing");
keyboardIsVisible = false;
if (wasOffset)
{
wasOffset = false;
[UIImageView beginAnimations:nil context:NULL];
[UIImageView setAnimationDuration:0.2f];
CGRect frame = mainView.frame;
frame.origin.y += offset;
mainView.frame = frame;
[UIImageView commitAnimations];
if (zoneButton.selected)
[popPickerController presentPopoverFromRect:zoneButton.frame inView:[zoneButton superview] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}