I have difficulty adding a subview (UIView) from within the viewDidLoad method of a UITableViewController
This works:
[self.view addSubview:self.progView];
But you can see the table cell lines bleed through the UIView progView.
I've tried this approach:
[self.view.superview insertSubview:self.progView aboveSubview:self.view];
Which is an attempt to add the progView, UIView to the superview, above the current view. When I try this, the UIView never appears.
-- UPDATE --
Following is the latest attempt:
UIView *myProgView = (UIView *)self.progView; //progView is a method that returns a UIView
[self.tableView insertSubview:myProgView aboveSubview:self.tableView];
[self.tableView bringSubviewToFront:myProgView];
Result is the same as [self.view addSubview:self.progView]; The UIView appears but seemingly behind the Table.
I tried the approach above, but did not get it to work. I also found it to require too much configuration and code, since it requires setting up the table view from scratch (something that is easily done from within the storyboard).
Instead, I added the view that I wanted to add above my UITableView into the UITableViewController's UINavigationController's view, as such:
[self.navigationController.view addSubview:<view to add above the table view>];
This approach requires that you have embedded the UITableViewController in a UINavigationController, but even if you do not want a navigation controller, you can still use this approach and just hide the navigation bar.
So 7 years have passed since my original answer, and I happen to stumble upon this problem again. Let's solve this properly once and for all:
In viewDidLoad, add your subview to the (table) view.
Pin the constraints relative to the safe area layout guide. This stops it from scrolling with the table contents (as pointed out in cornr's answer).
In viewDidLayoutSubviews, bring the subview to the front. This ensures it doesn't get lost behind the table separators.
Swift:
override func viewDidLoad() {
super.viewDidLoad()
// 1.
view.addSubview(mySubview)
// 2. For example:
mySubview.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
mySubview.widthAnchor.constraint(equalToConstant: 100),
mySubview.heightAnchor.constraint(equalToConstant: 100),
mySubview.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
mySubview.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor)
])
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// 3.
view.bringSubviewToFront(mySubview)
}
Objective-C:
- (void)viewDidLoad
{
[super viewDidLoad];
// 1.
[self.view addSubview:self.mySubview];
// 2.
self.mySubview.translatesAutoresizingMaskIntoConstraints = false;
[NSLayoutConstraint activateConstraints:#[
[self.mySubview.widthAnchor constraintEqualToConstant:100],
[self.mySubview.heightAnchor constraintEqualToConstant:100],
[self.mySubview.centerXAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.centerXAnchor],
[self.mySubview.centerYAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.centerYAnchor]
]];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
// 3.
[self.view bringSubviewToFront:self.mySubview];
}
Phew, glad that's done! Seeing how much saner this answer is, I'll omit my original answer.
Fun fact: 7 years on and I'm still an iOS developer.
Ive been able to add a subview on top of a uitableviewcontroller by using uiviewcontroller containment.
UITableViewController is actually very handy when it comes to static cells and this is probably the only time where the common answer "just use uitableview" may actually not viable.
So this is how I do it.
give your UITableViewController a StoryBoard identifier i.e. MyStaticTableView
create a brand new UIViewController subclass and call it UITableViewControllerContainer
place this controller in place of your UITableViewController inside your storyboard
add a subview to the new controller and link it to an outlet called like "view_container"
on you UITableViewControllerContainer viewDidLoad method
add code like:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UITableViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyStaticTableView"];
[self addChildViewController:vc];
[self.view_container addSubview:vc.view];
}
Problems you may have:
if you have extra top space then be sure to add the flag "wants fullscreen" to your UITableViewController
if it doesn't resize properly on your UITableViewControllerContainer
add code:
- (void)viewWillAppear:(BOOL)animated
{
[[self.view_container.subviews lastObject] setFrame:self.view.frame];
}
at this point from your UITableViewController you can access you container view directly with
self.view.superview.superview
and whatever you add to it will be show on top your table view controller
Swift 2018
Here is my way with storyboard:
1) Add a view in storyboard.
2) Link it with UITableViewController class:
#IBOutlet weak var copyrightLabel: UILabel!
3) Add it in code
self.navigationController?.view.addSubview(copyrightView)
copyrightView.frame = CGRect(x: 0,
y: self.view.bounds.size.height - copyrightView.bounds.size.height,
width: self.view.bounds.size.width,
height: copyrightView.bounds.size.height)
4) Voilla!
The view will not scroll with the table view. It can be easy designable from the storyboard.
NOTE:
This solution adds subview to the navigation controller and if you are going to another screen from here further down the nav, you will find this subview to persist, remove it using copyrightView.removeFromSuperView on viewDidDisappear while performing segue.
You can increase the zPosition of the layer of your view.
This will make it display above the other views (which have a zPosition equal to 0, by default)
self.progView.layer.zPosition++;
[self.view addSubview:self.progView];
As UITableViewController is a subclass of UIViewController, you need to add your desired view to its superview.
Swift:
self.view.superview?.addSubview(viewTobeAdded)
Objective C:
[self.view.superview addSubview: viewTobeAdded];
The problem is that the view property of UITableViewController is identical to the tableView property. What this means is that the root view is always a table view controller, and anything added as a subview will be subject to the table view functionality. This has other undesirable side effects, like your subviews scrolling when you may not want them to.
There are a couple options here. You could override loadView and install your own view and table view:
// note: untested
- (void)loadView {
self.view = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
self.view.backgroundColor = [UIColor whiteColor];
UITableView *tblView = [[UITableView alloc]
initWithFrame:CGRectZero
style:UITableViewStylePlain
];
tblView.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight
;
self.tableView = tblView;
[self.view addSubview:tblView];
[tblView release];
}
And then when you need to add a subview, add it below or above self.tableView as appropriate.
Another option is just to create a UIViewController subclass that does what you need. UITableViewController honestly doesn't add that much, and the little functionality it does implement is easily replicated. There are articles like Recreating UITableViewController to increase code reuse that explain how to do this pretty easily.
I had similar problem and got it solved using below code :
[self.navigationController.view insertSubview:<subview>
belowSubview:self.navigationController.navigationBar];
This inserts view in correct place using controllers present in Stack.
The Apple example "iPhoneCoreDataRecipes" is using a NIB to load a header onto a UITableView.
See here:
I added a image above the the table. I used this code:
self.tableView.tableHeaderView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"header.png"]];
Solution for swift (equivalent to Daniel Saidi):
If your controller is a UITableViewController in a Storyboard or XIB and you wish to reassign self.view to a standard UIView while preserving your existing table view:
#IBOutlet var tableViewReference: UITableView!
var viewReference: UIView!
Then in your implementation file:
Add these instance variables to your table view controller file:
override var tableView: UITableView! {
get { return tableViewReference }
set { super.tableView = newValue }
}
override var view: UIView! {
get { return viewReference }
set { super.view = newValue }
}
override func viewDidLoad() {
super.viewDidLoad()
self.edgesForExtendedLayout = UIRectEdge.None
self.extendedLayoutIncludesOpaqueBars = false
self.automaticallyAdjustsScrollViewInsets = false
//rewiring views due to add tableView as subview to superview
viewReference = UIView.init(frame: tableViewReference.frame)
viewReference.backgroundColor = tableViewReference.backgroundColor
viewReference.autoresizingMask = tableViewReference.autoresizingMask
viewReference.addSubview(tableViewReference)
}
In your Storyboard or XIB file: Connect the tableView in the UITableViewController to the tableViewReference variable.
Then you will be able to add child views as follows:
self.view.addSubView(someView)
Update for iOS 11:
It is now possible to add an Subview to UITableView when using AutoLayout constraints to the safe area. These Views will not scroll along the TableView.
This example places a view below the NavigationBar on top of the UITableView of a UITableViewController
[self.tableView addSubview:self.topBarView];
[NSLayoutConstraint activateConstraints:#[
[self.topBarView.topAnchor constraintEqualToAnchor:self.tableView.safeAreaLayoutGuide.topAnchor],
[self.topBarView.leadingAnchor constraintEqualToAnchor:self.tableView.safeAreaLayoutGuide.leadingAnchor],
[self.topBarView.trailingAnchor constraintEqualToAnchor:self.tableView.safeAreaLayoutGuide.trailingAnchor],
[self.topBarView.heightAnchor constraintEqualToConstant:40.0]
]];
try something like this:
[self.tableView addSubview:overlayView];
overlayView.layer.zPosition = self.tableView.backgroundView.layer.zPosition + 1;
You may simply put the following code in viewDidAppear:
[self.tableView.superview addSubview:<your header view>];
try: [self.view bringSubviewToFront:self.progView];
Or you can try to add self.progView to your table's view.
To keep UIView above table view in UITableViewController I'm using one(or more) of delegate methods (UITableViewDelegate).
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.addSubview(headerView)
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
tableView.addSubview(overlayView) // adds view always on top
}
// if using footers in table view
tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) { ... }
As views can only have one superview that seams too be good solution, correct me if I'm wrong. Still getting 60fps so it's fine for me.
Swift 4
This is the most simplified version of a number of answers here where we are recomposing the view hierarchy. This approach does not require additional outlets for storyboards / nibs and will also work with programmatically constructed instances.
class MyTableViewController: UITableViewController {
var strongTableView: UITableView?
override var tableView: UITableView! {
get {
return strongTableView ?? super.tableView
}
set {
strongTableView = newValue
}
}
override func viewDidLoad() {
super.viewDidLoad()
// theoretically we could use self.tableView = self.tableView but compiler will not let us assign a property to itself
self.tableView = self.view as? UITableView
self.view = UIView(frame: self.tableView!.frame)
self.view.addSubview(tableView)
}
}
To add a customView above the current UITableViewController, it must be a nice way to use 'self.navigationController.view addSubview:customView' like Daniel commented.
However, in case of implementing customView that serves as navigationBar, Daniel's way can cause unexpected result to default or custom navigationBar on other navigationViewControllers that is in front and back of the UITableViewController.
The best simple way is just converting UITableViewController into UIViewController which has no limit on layout it's subviews. But, if you're struggling with massive, long legacy UITableViewController code, the story is totally different. We don't have any sec for converting.
In this case, you can simply highjack tableView of UITableViewController and solve this whole problem.
The most important thing we should know is UITableViewController's 'self.view.superview' is nil, and 'self.view' is UITableView itself.
First, highjack the UITableVIew.
UITableView *tableView = self.tableView;
Then, replace 'self.view'(which is now UITableView) with a new UIView so that we can layout customViews with no-limitation.
UIView *newView = UIView.new;
newView.frame = tableView.frame;
self.view = newView;
Then, put UITableView we highjacked before on the new self.view.
[newView addSubview:tableView];
tableView.translatesAutoresizingMaskIntoConstraints = NO;
[tableView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
[tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
Now, we can do whatever we want on this brand new fancy 'self.view' on UITableViewController.
Bring a custom View, and just add as subView.
UIView *myNaviBar = UIView.new;
[myNaviBar setBackgroundColor:UIColor.cyanColor];
[self.view addSubview:myNaviBar];
myNaviBar.translatesAutoresizingMaskIntoConstraints = NO;
[myNaviBar.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[myNaviBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[myNaviBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
[myNaviBar.heightAnchor constraintEqualToConstant:90].active = YES;
gif
There may be reasons not to do this, but this works for me so far. If you use an ap
Inside viewDidLayoutSubviews you can run this, but make sure to only run it once obviously
self.searchTableView = [[UITableView alloc] initWithFrame:self.tableView.frame style:UITableViewStylePlain];
self.searchTableView.backgroundColor = [UIColor purpleColor];
[self.view.superview addSubview:self.searchTableView];
I had a similar problem where I wanted to add a loading indicator on top of my UITableViewController. To solve this, I added my UIView as a subview of the window. That solved the problem. This is how I did it.
-(void)viewDidLoad{
[super viewDidLoad];
//get the app delegate
XYAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
//define the position of the rect based on the screen bounds
CGRect loadingViewRect = CGRectMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2, 50, 50);
//create the custom view. The custom view is a property of the VIewController
self.loadingView = [[XYLoadingView alloc] initWithFrame:loadingViewRect];
//use the delegate's window object to add the custom view on top of the view controller
[delegate.window addSubview: loadingView];
}
This worked for me:
self.view.superview?.addSubview(yourCustomView)
self.view.bringSubviewToFront(yourCustomView)
Related
I am transiting my project to iOS7. I am facing a strange problem related to the translucent navigation bar.
I have a view controller and it has a tableview as subview (let's call it ControllerA) . I init a new uinavigationcontroller with the controllerA and present it modally using presentviewcontroller. The presented view controller's table view is blocked by the navigation bar. I set the automaticallyAdjustsScrollViewInsets to YES but the result did not change.
I knew I can set the edgesForExtendedLayout to UIRectEdgeNone, but it will make the navigation bar no more translucent.
After that, I tried to create a new view controller for testing. It contains almost the same elements. But the result is much different. The table view content does not get blocked.
Conclusion
Two View Controllers' automaticallyAdjustsScrollViewInsets set to YES
The project is not using storyboard
The first one is created at Xcode 4.6, The second one is newly created on Xcode 5
I have compared two classes xib and code, not much different
I have found the answer on apple developer forum.
There are two different case.
The first one, the view controller added is a UITableViewController.
And the issue should not be appeared since apple will auto padding it.
The second one, the view controller is NOT a UITableViewController.
And in the view hierarchy, it contains a UITableView. In this case, if the UITableview(or ScrollView) is the viewController's mainview or the first subview of the mainview, it will work. Otherwise, the view controller doesn't know which scroll view to padding and it will happen the issue.
In my case, the view controller is the second one. And there is a background image view as the first subview of the main view. So, it fails.
Here is the Apple developer forum link (need developer account to access):
https://devforums.apple.com/message/900138#900138
If you want the view to underlap the navigation bar, but also want it positioned so the top of the scrollview's content is positioned below the navigation bar by default, you can add a top inset manually once the view is laid out. This is essentially what the view layout system does when the top-level view is a scroll view.
-(void)viewDidLayoutSubviews {
if ([self respondsToSelector:#selector(topLayoutGuide)]) {
UIEdgeInsets currentInsets = self.scrollView.contentInset;
self.scrollView.contentInset = (UIEdgeInsets){
.top = self.topLayoutGuide.length,
.bottom = currentInsets.bottom,
.left = currentInsets.left,
.right = currentInsets.right
};
}
}
Based on Tony's answer I was able to get around this problem programatically with temporarily sending the table view to the back, let the adjustments be made and then send the background view back to the back. In my case there is no flickering to this approach.
In the View Controller:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.view sendSubviewToBack:self.tableView];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.view sendSubviewToBack:self.backgroundView];
}
Obviously if there are other subviews on self.view you may need to re-order those too.
There's probably too many answers on this already, but I had to take Christopher's solution and modify it slightly to support view resizing and allowing the content inset to be changed in a subclass of the UIViewController.
#interface MyViewController ()
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property (assign, nonatomic) UIEdgeInsets scrollViewInitialContentInset;
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setScrollViewInitialContentInset:UIEdgeInsetsZero];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
if (UIEdgeInsetsEqualToEdgeInsets([self scrollViewInitialContentInset], UIEdgeInsetsZero)) {
[self setScrollViewInitialContentInset:[self.scrollView contentInset]];
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIEdgeInsets scrollViewInset = [self scrollViewInitialContentInset];
if (UIEdgeInsetsEqualToEdgeInsets(scrollViewInset, UIEdgeInsetsZero) {
if ([self respondsToSelector:#selector(topLayoutGuide)]) {
scrollViewInset.top = [self.topLayoutGuide length];
}
if ([self respondsToSelector:#selector(bottomLayoutGuide)]) {
scrollViewInset.bottom = [self.bottomLayoutGuide length];
}
[self.scrollView setContentInset:scrollViewInset];
}
}
#end
To explain the point:
Any subclass of MyViewController can now modify the contentInset of scrollView in viewDidLoad and it will be respected. However, if the contentInset of scrollView is UIEdgeInsetsZero: it will be expanded to topLayoutGuide and bottomLayoutGuide.
#Christopher Pickslay solution in Swift 2:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let topInset = topLayoutGuide.length
inTableView.contentInset.top = topInset
inTableView.contentOffset.y = -topInset
inTableView.scrollIndicatorInsets.top = topInset
}
Yeah - a bit annoying.
I have a nib with a single tableview within the main view, not using autolayout. There is a tabbar, navigationbar and a statusbar and the app needs to work back to 5.0. In Interface builder that neat 'see it in iOS7 and iOS6.1 side-by-side' thing works, showing the tables neatly fitting (once the iOS6/7 deltas were set properly).
However running on a device or simulator there was a large gap at the top of the table, which was as a result of a content inset (which pretty much matched by iOS6/7 vertical delta) that was set to zero in the nib.
Only solution I got was in viewWillAppear to put in [_tableView setContentInset:UIEdgeInsetsZero].
Another ugly hack with a pretty on-screen result.....
[self.navigationController setNavigationBarHidden:YES animated:YES];
in:
- (void)viewDidLoad
I'm having an issue receiving touches in UICollectionViews contained within UITableViewCells. The desired effect is a UITableView with n rows of horizontally scrolling UICollectionViews. The view is displaying correctly but the collection views only receive touches in the top 44px. I imagine that the table view is still in the process of initialization when the collection views are created and that the collection views are using UITableView's default cell height when setting up their gesture recognizers. Relevant code is below.
In my UITableViewCell subclass, I create a container view for the UICollectionView:
- (void)layoutSubviews
{
if (!_collectionViewContainer) {
_collectionViewContainer = [[CVTCollectionViewContainer alloc] init];
_collectionViewContainer.frame = self.bounds;
[self.contentView addSubview:_collectionViewContainer];
};
}
In my container view, I instantiate a UICollectionView:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
if (!self.collectionView) {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:flowLayout];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.backgroundColor = [UIColor clearColor];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.itemSize = CGSizeMake(130.0, 130.0);
[_collectionView registerClass:[CVTCollectionViewCell class] forCellWithReuseIdentifier:#"Collection view cell"];
[self addSubview:self.collectionView];
}
}
There's nothing interesting in my UITableViewController, just that I return 200 in tableView:heightForRowAtIndexPath:
It occurred to me that the layoutSubviews method of my UITableViewCell subclass may be the wrong place for initialization of the 'container' view for my UICollectionView. But, when I NSLog(#"cell: %#", self); in layoutSubviews, the cell's frame shows the desired height (200). Still, I have a feeling that I am doing my setup for the collection view too early, but I can't think of where else I might perform this work.
So, the gist: how can I add a UICollectionView to a UITableViewCell and make sure that the UICollectionView's gesture recognizers respond in the entirety of the collection view, rather than just the top 44 px?
Thanks in advance, as always.
Bit of a facepalm here, I was using a UITableViewController that was created in storyboard but mostly configured in code. In storyboard, I had not set the row height of the table view, so it was still at the default 44 px. Of course, the table view looked at IB for its initial config so, although tableView:heightForRowAtIndexPath: was being called and the cells were displaying correctly, the initial height set in IB was affecting how the cell's subviews were created.
I'm building an app for a blog site.
I have a UINavigationController with a UITableViewController as it's root view.
I laid this out in a storyboard no problem, but I'm trying to drag an iAd view to the bottom of the screen and xcode will not let me add it.
It looks like I have to switch from a subclass of UITableViewController to a subclass of UIViewController, and just put my delegate and datasource methods in my subclassed UIViewController.
This seems wrong to me. I'm just trying to end up with a UITableView of article headlines, with a navbar up top, and an iAd at the bottom...
Advice? Suggestions?
Thanks in advance.
One of the easiest ways to accomplish this is using the UITableView's tableFooterView property. Yes, I know the footer stays at the bottom of the table, but it doesn't have to. You can set its frame within the table. Add the iAd as the footer like so:
self.tableView.tableFooterView = iAd;
Then, to adjust the frame of the iAd as the table scrolls, implement the UIScrollView delegate method: (This is possible because UITableView is a subclass of UIScrollView)
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGRect iAdFrame = iAd.frame;
CGFloat newOriginY = table.contentOffset.y + table.frame.size.height - iAdFrame.size.height;
CGRect newIAdFrame = CGRectMake(iAdFrame.origin.x, newOriginY, iAdFrame.size.width, iAdFrame.size.height);
iAd.frame = newIAdFrame;
}
You can see that the implementation is easy enough. We simply use the contentOffset y to determine how far down the frame of the iAd should be.
I tried to use the example above by NJones with adjusting the position of the tableFooterView, but I found out it was hard to manage it when reloading the data or refreshing the table.
Then I found out that this could be done by adding the iAd banner to the superview of the tableViewController's view.
self.bannerViewController = [[BannerViewController alloc] init];
[self.bannerViewController.view setHidden:YES];
[self.bannerViewController.view setFrame:CGRectMake(0, self.view.superview.frame.size.height - self.tabBarController.tabBar.frame.size.height - 50, 320, 50)];
[self.view.superview addSubview:self.bannerViewController.view];
[self.bannerViewController loadBanner];
When the banner is loaded I create a tableFooterView to make space for the last cell in the tableViewController
-(void)bannerDidLoad{
[self.bannerViewController.view setHidden:NO];
self.tableView.tableFooterView = [[UIView alloc];
initWithFrame:self.bannerViewController.view.frame];
}
I had to make some changes to the solution posted by NJones, since there was a problem with the ad not being displayed on top of all other cells/views.
First make sure your tableViewController is a AdBannerViewDelegate:
#interface MyTableViewController () <ADBannerViewDelegate>
Adding the AdBanner to the tableviewcontroller:
- (void)viewDidLoad {
[super viewDidLoad];
...
ADBannerView *adBanner = [[ADBannerView alloc]initWithAdType:ADAdTypeBanner];
adBanner.delegate = self;
self.tableView.tableFooterView = adBanner;
}
The code to position the ad banner is taken from NJones, I only added the last line to bring the ad banner to the front:
-(void)positionAdBanner {
ADBannerView *adBanner = (ADBannerView *) self.tableView.tableFooterView;
if (adBanner) {
CGRect iAdFrame = adBanner.frame;
CGFloat newOriginY = self.tableView.contentOffset.y + self.tableView.frame.size.height - iAdFrame.size.height;
CGRect newIAdFrame = CGRectMake(iAdFrame.origin.x, newOriginY, iAdFrame.size.width, iAdFrame.size.height);
adBanner.frame = newIAdFrame;
[self.tableView bringSubviewToFront:adBanner];
}
}
This function gets called whenever the view is going to layout its subviews (so you only need it here, no need to check for scrolling, etc):
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
[self positionAdBanner];
}
You also should handle the ADBannerViewDelegate methods:
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
banner.hidden = NO;
[self positionAdBanner];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
banner.hidden = YES;
}
I'm searching for a way to have a UITableViewController with a UITableView at the top and a UIPickerView bellow (with fix position).
I've found a solution for fixing the picker with the code bellow:
- (void)viewDidLoad {
[super viewDidLoad];
_picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
_picker.showsSelectionIndicator = YES;
_picker.dataSource = self;
_picker.delegate = self;
// Add the picker to the superview so that it will be fixed
[self.navigationController.view addSubview:_picker];
CGRect pickerFrame = _picker.frame;
pickerFrame.origin.y = self.tableView.frame.size.height - 29 - pickerFrame.size.height;
_picker.frame = pickerFrame;
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.size.height = 215;
self.tableView.frame = tableViewFrame;
[_picker release];
}
The problem is with the tableview, it seems resizing doesn't work so I can't see all results .
Thanks for your advice.
You should use a UIViewController subclass instead of UITableViewController to manage a table view if the view to be managed is composed of multiple subviews, one of which is a table view. You can add a UITableView subview and make your controller implement UITableViewDelegate and UITableViewDataSource protocols.
The default behavior of the UITableViewController class is to make the table view fill the screen between the navigation bar and the tab bar (if either are present).
From Table View Programming Guide for iOS:
Note: You should use a
UIViewController subclass rather than
a subclass of UITableViewController to
manage a table view if the view to be
managed is composed of multiple
subviews, one of which is a table
view. The default behavior of the
UITableViewController class is to make
the table view fill the screen between
the navigation bar and the tab bar (if
either are present).
If you decide to
use a UIViewController subclass rather
than a subclass of
UITableViewController to manage a
table view, you should perform a
couple of the tasks mentioned above to
conform to the human-interface
guidelines. To clear any selection in
the table view before it’s displayed,
implement the viewWillAppear: method
to clear the selected row (if any) by
calling deselectRowAtIndexPath:animated:.
After the table view has been
displayed, you should flash the scroll
view’s scroll indicators by sending a
flashScrollIndicators message to the
table view; you can do this in an
override of the viewDidAppear: method
of UIViewController.
I realize this is a popular topic, and I've searched through many posts here but haven't found anything that has helped my issue. I'm a beginner, for what it's worth (as you'll see by my question :-)
My app has a tab bar with 3 items. The first loads a UINavigationController that is intended to have 3 "screens" to drill-down through (first: UITableView, second: filtered UITableView, third: UIView). I cannot, for the life of me, figure out how to show the UITableView on the 2nd screen, programmatically.
I'm overriding - (void)loadView since I'm not using IB. At different times, I've tried things like:
- (void)loadView
{
[super loadView];
// first option (thought for sure this would work)
[[self view] addSubview:secondTableView];
// another...
[self tableView:secondTableView];
// another...
[[[[self navigationController] topLevelController] view] addSubview:secondTableController];
}
I do have the table view setup properly with it's delegate and datasource, I just can't figure out how to show the damn thing. The 2nd controller is also inheriting from UITableViewController. Additionally, I don't know how you can say "fit this table view within the navigation title and the tab bar menu". I'm using CGRectMake() currently to guess the sizes, but it seems like there should be a better way (maybe that's why you use IB :-). Either way, that's secondary to even getting something to show up in the first place.
Thanks in advance for any suggestions.
If you're inheriting from UITableViewController your view should be a UITableView not a plain UIView, then when you want to create a view programmatically you should allocate it, initialize it, set its properties and assign it as your controller's view, I haven't tried [super loadView] before but it's creating the tableView for you and assigning dataSource and delegate to self, so you don't have to do that. So it should go like this
- (void)loadView {
UITableView *tempPointer = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480) andStyle:UITableViewStylePlain];
self.view = tempPointer; // controller retains view property so we should release it
[tempPointer release];
// If you want your view to be resized automatically (to fit)
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.tableView.dataSource = self;
self.tableView.delegate = self;
//...
}
or
- (void)loadView {
[super loadView];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
secondTableView = self.tableView; // or change your code to cope with self.tableView instead of secondTableView...
//...
}
Clear out some uncertainties about view hierarchy creation, retaining etc in the documentation about both UIViewController and UITableViewController if you haven't already.
have you tried:
[Self.navigationController pushViewController:secondTableView];
Hope this helps, if not could you give a little more describing the situation.