How to add a UIView above the current UITableViewController

IphoneObjective CIos4

Iphone Problem Overview


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.

Iphone Solutions


Solution 1 - Iphone

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.

Solution 2 - Iphone

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:

  1. In viewDidLoad, add your subview to the (table) view.
  2. 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).
  3. 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.

Solution 3 - Iphone

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.

  1. give your UITableViewController a StoryBoard identifier i.e. MyStaticTableView
  2. create a brand new UIViewController subclass and call it UITableViewControllerContainer
  3. place this controller in place of your UITableViewController inside your storyboard
  4. add a subview to the new controller and link it to an outlet called like "view_container"
  5. 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:

  1. if you have extra top space then be sure to add the flag "wants fullscreen" to your UITableViewController
  2. 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

Solution 4 - Iphone

###Swift 2018### Here is my way with storyboard:

  1. Add a view in storyboard.
    enter image description here

  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!
    enter image description here

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.

Solution 5 - Iphone

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];

Solution 6 - Iphone

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];

Solution 7 - Iphone

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.

Solution 8 - Iphone

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.

Solution 9 - Iphone

The Apple example "iPhoneCoreDataRecipes" is using a NIB to load a header onto a UITableView. See here:

Solution 10 - Iphone

I added a image above the the table. I used this code:

self.tableView.tableHeaderView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"header.png"]];

Solution 11 - Iphone

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)

Solution 12 - Iphone

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]
]];

Solution 13 - Iphone

try: [self.view bringSubviewToFront:self.progView];

Or you can try to add self.progView to your table's view.

Solution 14 - Iphone

try something like this:

[self.tableView addSubview:overlayView];
overlayView.layer.zPosition = self.tableView.backgroundView.layer.zPosition + 1;

Solution 15 - Iphone

You may simply put the following code in viewDidAppear:

[self.tableView.superview addSubview:<your header view>];

Solution 16 - Iphone

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.

Solution 17 - Iphone

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)
                    
    }
    
}

Solution 18 - Iphone

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

Solution 19 - Iphone

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]; 
}

Solution 20 - Iphone

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];

Solution 21 - Iphone

This worked for me:

self.view.superview?.addSubview(yourCustomView)
self.view.bringSubviewToFront(yourCustomView)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser558096View Question on Stackoverflow
Solution 1 - IphoneDaniel SaidiView Answer on Stackoverflow
Solution 2 - IphoneThomas VerbeekView Answer on Stackoverflow
Solution 3 - IphoneNicola FerruzziView Answer on Stackoverflow
Solution 4 - IphoneNike KovView Answer on Stackoverflow
Solution 5 - IphonePaco_777View Answer on Stackoverflow
Solution 6 - IphoneSaikiran KomirishettyView Answer on Stackoverflow
Solution 7 - IphoneJustin Spahr-SummersView Answer on Stackoverflow
Solution 8 - IphoneJayprakash DubeyView Answer on Stackoverflow
Solution 9 - IphoneOlafView Answer on Stackoverflow
Solution 10 - IphoneCarmenView Answer on Stackoverflow
Solution 11 - IphoneD. SergeevView Answer on Stackoverflow
Solution 12 - IphonecornrView Answer on Stackoverflow
Solution 13 - IphoneWrightsCSView Answer on Stackoverflow
Solution 14 - IphoneFilip RajView Answer on Stackoverflow
Solution 15 - IphoneMig70View Answer on Stackoverflow
Solution 16 - IphoneTomasz KwolekView Answer on Stackoverflow
Solution 17 - IphoneBrody RobertsonView Answer on Stackoverflow
Solution 18 - IphoneRoss ButlerView Answer on Stackoverflow
Solution 19 - IphoneSalman Hasrat KhanView Answer on Stackoverflow
Solution 20 - IphoneBob SprynView Answer on Stackoverflow
Solution 21 - IphonellehcramView Answer on Stackoverflow