I'm trying to resize my tableView when I am have an AdMob view at the bottom of my screen. I've tried a couple things: Change UITableView height dynamically and Resizing UITableView When Displaying AdWhirl Ads Across Multiple Views and Change size of UIViewTable to accommodate for AdWhirl Ad but none of those have worked. By not worked, I mean NOTHING happens. The view is EXACTLY the same as it was before I tried those changes. So you know, this tableView is nested inside of a ViewController. Here is the layout:
Here is the last thing I've tried:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:NO];
#ifdef FREERECORDER
CGPoint origin = CGPointMake(0.0,self.view.frame.size.height - 90 - CGSizeFromGADAdSize(kGADAdSizeBanner).height);
gBannerView =[[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner
origin:origin];
//this is where I'm attempting to resize
CGRect tableFrame = self->tableView.frame;
tableFrame.size.height = self->tableView.frame.size.height - 500;
self->tableView.frame = tableFrame;
gBannerView.adUnitID = #"MY_AD_ID";
gBannerView.rootViewController = self;
[self.view addSubview:gBannerView];
GADRequest *request = [GADRequest request];
// Make the request for a test ad. Put in an identifier for
// the simulator as well as any devices you want to receive test ads.
request.testDevices = [NSArray arrayWithObjects:
#" MY_TEST_ID",
nil];
[gBannerView loadRequest:[GADRequest request]];
#endif
self.title = #"All Root Beers";
RootBeerFeedParser* rfp = [[RootBeerFeedParser alloc]init];
rootBeerList = [rfp getCoreDataRootBeers];
self.tabBar.delegate = self;
[self->tableView reloadData];
}
This is the result:
![enter image description here][2]
What it doesn't show, is that the last cell in the tableview is covered by that advertisement and I'm trying to fix that.
If you want to resize tableView by updating its frame, then you should turn off the autolayout mode. With autolayout you should update constrains but not frames.
You should implement updateConstraints (http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instm/UIView/updateConstraints) in order to specify the new requirement.
You may also need to call setNeedsUpdateConstraints at some point in time (if you need to show and hide the ad view).
Related
I can't figure out how to change my AdMob banner's background color when the ad doesn't fit. Is this possible? The code below wouldn't work for me.
self.ad.backgroundColor= [UIColor whiteColor];
This is actually achieved through AdMob's dashboard.
Go to AdMob.com
Select Monetize on the top toolbar
Select the application on the left side bar that you want to change the background color for
Select the Ad Unit of the banner
In the Text ad style drop down menu select Customized
Select Background color and change it to whichever color you desire
Select Save and you're all done
It may take a few minutes for changes to appear in your application.
You could add your GADBannerView to another UIView that you set the backgroundColor of. This would require using AdMob's default sizes to make sure that image banners fit properly. The down fall of this is that text based ads will be restricted to this size also instead of filling the entire ad area.
For example:
#import "ViewController.h"
#import GoogleMobileAds;
#define ADUNIT_ID #"yourAdUnitID"
#interface ViewController () <GADBannerViewDelegate> {
GADBannerView *admobBanner;
UIView *backgroundView;
}
#end
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
// Create our AdMob banner
admobBanner = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];
admobBanner.adUnitID = ADUNIT_ID;
admobBanner.rootViewController = self;
admobBanner.delegate = self;
[admobBanner loadRequest:[GADRequest request]];
// Create a view to put our AdMob banner in
backgroundView = [[UIView alloc]initWithFrame:CGRectMake(0,
self.view.frame.size.height - admobBanner.frame.size.height,
self.view.frame.size.width,
admobBanner.frame.size.height)];
// Hide view until we have an ad
backgroundView.alpha = 0.0;
// Set to color you require
backgroundView.backgroundColor = [UIColor redColor];
// Add our views
[self.view addSubview:backgroundView];
[backgroundView addSubview:admobBanner];
// Center our AdMob banner in our view
admobBanner.center = [backgroundView convertPoint:backgroundView.center fromView:backgroundView.superview];
}
-(void)adViewDidReceiveAd:(GADBannerView *)adView {
NSLog(#"adViewDidReceiveAd");
[UIView animateWithDuration:0.5 animations:^{
backgroundView.alpha = 1.0;
}];
}
-(void)adView:(GADBannerView *)adView didFailToReceiveAdWithError:(GADRequestError *)error {
NSLog(#"adView:didFailToReceiveAdWithError: %#", [error localizedDescription]);
[UIView animateWithDuration:0.5 animations:^{
backgroundView.alpha = 0.0;
}];
}
iPhone / iPad
You should insert the ad in a container view.
Then, in the delegate that is called when the ad is loaded adjust the container width to be the same size as the ad view
You need to start by figuring out what views compose the ad view. Probably you are changing the view's color, but it has another view on top of it that contains the ad, and total blocks the parent view.
Start by placing a breakpoint in your code (I often place it in -viewDidAppear:) and once in there, type this in the debugger to see the subviews of the ad view:
po self.ad.subviews
My guess is that you'll see one subview that stretches the full length of the main window. It may even be a UIImageView that contains the ad image. But you can continue to look at the subviews of the subviews, either in the debugger or by adding code in -viewDidAppear:.
This is probably view you want to mess with. In -viewDidAppear:, try adding code to color the subview's background instead:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIView *adSubview = self.ad.subviews.firstObject;
adSubview.backgroundColor = [UIColor whiteColor];
}
This code should be safe even if the ad or its subviews property returns nil.
I think you should fill rect of UIView same Admob size.
bannerView = GADBannerView(frame: rectBanner)
bannerView.adUnitID = "xxxxxxxxxxxxxxxxxx"
bannerView.rootViewController = self
frame size(rectBanner) should be match with Admob Size.
I have an project using autolayout,
And I notice that after viewWillAppear, viewWillLayoutSubViews and viewDidLayoutSubViews pair will be called several times on iOS 8, for my case, it is 2-3 times usually.
The fist viewDidLayoutSubViews will get incorrect frame size, so I have to avoid for first viewDidLayoutSubViews, and init my views afterwards.
However, when I tested it on iOS 7, I found that only ONE viewWillLayoutSubViews and viewDidLayoutSubViews pair got called, so my code broke again.
My question is, what is changed on iOS 8 for this behaviour?
EDIT:
I have pasted my demo code here:
In the code, _pieChart will be added to self.ChartViewCanvas, and self.ChartViewCanvas is using autolayout. _pieChart is from old project code, which is drawn without auto layout.
I was required to draw the pie chart before viewDidAppear, because drawing in viewDidAppear will have a 1 sec delay compare to other views in storyboard. This is not allowed for me.
Is there any way to know when is the final viewDidLayoutSubViews? Calling [self.ChartViewCanvas addSubview:_pieChart]; multiple times will lead to lower performance, and sometimes _pieChart's drawInRect will not be called every time, so the chart is not update.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
_pieChart.delegate = self;
if (!_pieChart) {
_pieChart = [[PieChartView alloc] initWithFrame:CGRectMake(0, 0, pieRadius * 2, pieRadius * 2)];
}else {
[_pieChart setFrame:CGRectMake(0, 0, pieRadius * 2, pieRadius * 2)];
}
//_pieChart.translatesAutoresizingMaskIntoConstraints = NO;
if ([_pieChart superview]) {
[_pieChart removeFromSuperview];
}
[self.ChartViewCanvas addSubview:_pieChart];
}
Probably only Apple knows, but I won't deal with that too much if everything is working fine. In iOS8 Apple changed a lot view controllers (again) in they way they are presented from containers VC as for rotation and UITraitCollections.
For instance UIAlertView is now a view controller, when you show one you trigger all the mechanism related to present a VC.
If this fact is creating an issue it must be said that you should not rely on how many times those methods are called because they were always be unpredictable there are too many variables to be taken into account.
A quick and dirty solution could be wrap your code in a dispatch_once if you want that it will be called only one time.
If you add your view using auto layout correctly you won't see any sort of bug.
[EDIT]
Here is a little snippet about how it might look your viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
//.. your stuff
//We don't need any frame autolayout wil take care of calculating it on its pass
_pieChart = [[PieChartView alloc]initWithFrame:CGRectZero];
_pieChart.delegate = self;
_pieChart.translatesAutoresizingMaskIntoConstraints = NO;
[self.ChartViewCanvas addSubview:_pieChart];
NSDictionary *bindings = NSDictionaryOfVariableBindings(_pieChart);
// We create constraints to tell the view that it needs to sctretch its bounds to the superview
NSString *formatTemplate = #"%#:|[_pieChart]|";
for (NSString * axis in #[#"H",#"V"]) {
NSString * format = [NSString stringWithFormat:formatTemplate,axis];
NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:bindings];
[_pieChart.superview addConstraints:constraints];
}
// Do any additional setup after loading the view.
}
Of course that is going to call drawRect:, draw rect is called when a view is marked as dirty in the display pass, but before display is usually called the autolayout engine to calculate frames of views in needs for layout.
I tried this out on my application and found the same as you: 1 call on iOS7 and 3 on iOS8. From the stack traces this seems to be down to doing double layout after viewWillAppear and an extra layout following viewDidAppear not seen on iOS7.
My suggestion would be that you add any views in viewDidLoad (or viewWillAppear), then only do layout adjustments in the layout subview runs. Based on your updated post something like:
- (void)viewDidLoad{
[super viewDidLoad];
_pieChart = [[PieChartView alloc] initWithFrame:CGRectMake(0, 0, pieRadius * 2, pieRadius * 2)];
[self.ChartViewCanvas addSubview:_pieChart];
_pieChart.delegate = self;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[_pieChart setFrame:CGRectMake(0, 0, pieRadius * 2, pieRadius * 2)];
}
For interest the difference between iOS7 and 8 calling sequence was:
iOS7
i) viewWillAppear is called.
ii) layout of subviews is called. From the stack this seems to relate to the navigation bar and animation.
ii) viewDidAppear is called.
iOS8
i) viewWillAppear is called.
ii) layout of subviews is called. From the stack this seems to relate to the navigation bar and animation.
iii) exact same layout with exact same stack is called again. So something in the stack must request a rerun from some point.
iv) viewDidAppear is called.
v) An extra layout of subviews is called. This seems driven from a transaction pushed onto the run loop.
I'm working on example from "iOS Programming Cookbook", based on iOS 7. I need to create UITextField and add it to ViewController.
In ViewController.m I have:
- (void) viewDidLoad {
[super viewDidLoad];
[self createField];
}
- (void) createField {
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(20.0f, 35.0f, 280.0f, 30.0f)];
self.textField.translatesAutoresizingMaskIntoConstraints = NO;
self.textField.borderStyle = UITextBorderStyleRoundedRect;
self.textField.placeholder = #"Enter text to share";
self.textField.delegate = self;
[self.view addSubview:self.textField];
}
On screenshot from book textField appears in the middle of screen's width under the status bar, but when I run it textField appears on the top left corner of screen behind the status bar.
Maybe the problem is, that I run app on iPhone 6 simulator with iOS 8. But I don't know how to solve it.
Thanks!
Using self.textField.translatesAutoresizingMaskIntoConstraints = NO; is pretty much telling the object that it doesn't really care about the frame but relies more on the constraints that you give it. Setting it to YES takes the frame and automatically applies constraints to it to mimic the frame that you give it.
For example it would apply the constraints to have the frame appear at: CGRectMake(20.0f, 35.0f, 280.0f, 30.0f). When setting it to NO use NSLayoutConstraint and create the constraints programatically.
But in your case just remove the line
self.textField.translatesAutoresizingMaskIntoConstraints = NO;
because it is set to YES by default.
I'm trying to display a UIButton over an AdmobBanner like the example below (the black X obviously). I looked for this option in the Admob SDK but couldn't find anything.
I've tried selecting the button->Editor->Arrange->Send to Front with no results.
Help is much appreciated.
This is the code I use to show my banner:
CGPoint origin = CGPointMake(0.0,0.0);
// Use predefined GADAdSize constants to define the GADBannerView.
self.adBanner = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner
origin:origin];
// Note: Edit SampleConstants.h to provide a definition for kSampleAdUnitID
// before compiling.
self.adBanner.adUnitID = #"a150xxxxxxxxxxx";
self.adBanner.delegate = self;
[self.adBanner setRootViewController:self];
[self.view addSubview:self.adBanner];
self.adBanner.center =
CGPointMake(self.view.center.x, self.adBanner.center.y);
[self.adBanner loadRequest:[self createRequest]];
Im assuming you're using interface builder here, and that both the AdMob view and your button are subviews of the same parent view. If that is the case, just make sure the button comes before the AdMob view in the list of subviews in the Objects pane on the left.
Another option is to make the following call in viewDidLoad:
[self.view bringSubviewToFront:button]
Make sure you do this after inserting the AdMob view, if you're doing it programmatically
I'm using altered sample code from PhotoScroller within my app. I have a table view of image thumbnails, and I can pass the array of images that populate that table to PhotoViewController. Currently, PhotoViewController starts with the first image in my array and I can scroll back and forth. This works properly as Apple's sample code.
Now What I want to do is tap a table cell with thumbnail, and start scrolling images beginning with the image in my array at that index. Ex: if I have 5 images in a table and I tap image #3, I want the first image in PhotoViewController to be that third image, and able to scroll left or right to #2 or #4. Hope this makes sense.
I see in PhotoViewController that sub views are being added per image. Any way I can tell it "jump to view #3" without destroying the other views or their overall order of appearance? Any ideas or advice is welcome. Code can be found on the iOS developer site for PhotoScroller sample code.
Ok, I'm rambling... Thanks in advance for your help!
The way I do this is to have a variable called startingPage which gets set in the initialiser of the photo view controller. Then when the pages are being created, first set the correct offset for the scroll view.
So in the PhotoScroller case that would be in loadView. Like so:
- (void)loadView
{
// Step 1: make the outer paging scroll view
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
pagingScrollView.pagingEnabled = YES;
pagingScrollView.backgroundColor = [UIColor blackColor];
pagingScrollView.showsVerticalScrollIndicator = NO;
pagingScrollView.showsHorizontalScrollIndicator = NO;
pagingScrollView.contentSize = [self contentSizeForPagingScrollView];
pagingScrollView.delegate = self;
self.view = pagingScrollView;
// Set the content offset of the scrollview
CGRect bounds = pagingScrollView.bounds;
CGPoint contentOffset = CGPointMake(bounds.size.width * startingPage, 0.0f);
[pagingScrollView setContentOffset:contentOffset animated:NO];
// Step 2: prepare to tile content
recycledPages = [[NSMutableSet alloc] init];
visiblePages = [[NSMutableSet alloc] init];
[self tilePages];
}