27

I need to put a UIView (for ads) on top of a UITableView in my iphone app. The problem is that when I scroll the table to the bottom the added UIView is scrolling with the table. What I want is for it to be fixed on the bottom of the screen. Is there a way to do that?

This is the code which I have used to add the UIView to the table:

 awView = [AdWhirlView requestAdWhirlViewWithDelegate:self]; 
 awView.autoresizingMask=UIViewAutoresizingFlexibleLeftMargin;
 [self.tableView addSubview:awView];
Marcus Leon
  • 55,199
  • 118
  • 297
  • 429
Mohamed Emad Hegab
  • 2,665
  • 6
  • 39
  • 64
  • notes ... http://stackoverflow.com/questions/8258216/position-a-uiview-relative-to-the-bottom-of-the-parent-view/20287309#20287309 – Fattie Nov 29 '13 at 15:28
  • I think all of the answers below are confused. What you do is add your view to the superview of the table view. Simple as that. – Jonny Apr 17 '17 at 09:21

6 Answers6

33

Here is how it worked for me. The Ad stays at the bottom of the view.

In ViewDidLoad, in YourController.m:

awView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
awView.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height-kAdWhirlViewHeight/2);
[self.view addSubview:awView];

Then add this method somewhere in the same .m file:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGRect newFrame = awView.frame;
    newFrame.origin.x = 0;
    newFrame.origin.y = self.tableView.contentOffset.y+(self.tableView.frame.size.height-kAdWhirlViewHeight);
    awView.frame = newFrame;
}

Don't forget to declare awView.

Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
lucasart
  • 1,643
  • 1
  • 20
  • 29
29

I appreciate this is an old question. But I've found the answers either with false information in part and unclear snippets. So for what it's still worth, here is how I added a "floating" view to the bottom of my UITableViewController's view. Yes, you can do that, even if the accepted answers says you cannot.

In your -viewDidLoad method, you can create a view which we will name bottomFloatingView. This is also set up as a property.

Be sure to add a content inset to the bottom of your table view, this will avoid hiding any of the table's content with your floating view.

Next, you should use the UIScrollViewDelegate to update the frame of the floating view.

The illusion will be that your view is stuck to the bottom. In reality, this view is moving all the time you are scrolling, and is always being computed to appear at the bottom. Scroll views are very powerful ! And probably are one of the most underrated UIKit classes I think.

So here is my code. Note the property, the content inset on the table view and the -scrollViewDidScroll: delegate method implementation. I created my floating view in my storyboard which is why you can't see that being setup.

Also don't forget you should probably also use KVO to observe changes to the table view's frame. It's possible for that to change over time, the easiest way to test that is by toggling on and off the in call status bar in the simulator.

Last thing, if you're using section header views in your table view, those views will be the top most view in the table view so you'll also want to bring your floating view to the front, do this when you change its frame.

@interface MyTableViewController ()
@property (strong, nonatomic) IBOutlet UIView *bottomFloatingView;
@end

@implementation MyTableViewController

static NSString *const cellIdentifier = @"MyTableViewCell";

- (void)dealloc
{
    [self.tableView removeObserver:self forKeyPath:@"frame"];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.tableView addSubview:self.bottomFloatingView];

    self.tableView.contentInset = UIEdgeInsetsMake(0.0, 0.0, CGRectGetHeight(self.bottomFloatingView.bounds), 0.0);
    self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0.0, 0.0, CGRectGetHeight(self.bottomFloatingView.bounds), 0.0);

    [self.tableView addObserver:self
                     forKeyPath:@"frame"
                        options:0
                        context:NULL];
}

#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    cell.textLabel.text = [NSString stringWithFormat:@"Row %d", indexPath.row];

    return cell;
}

#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    [self adjustFloatingViewFrame];
}

#pragma mark - KVO

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
    if([keyPath isEqualToString:@"frame"]) {
        [self adjustFloatingViewFrame];
    }
}

- (void)adjustFloatingViewFrame
{
    CGRect newFrame = self.bottomFloatingView.frame;

    newFrame.origin.x = 0;
    newFrame.origin.y = self.tableView.contentOffset.y + CGRectGetHeight(self.tableView.bounds) - CGRectGetHeight(self.bottomFloatingView.bounds);

    self.bottomFloatingView.frame = newFrame;
    [self.tableView bringSubviewToFront:self.bottomFloatingView];
}

@end
Daniel
  • 23,129
  • 12
  • 109
  • 154
  • awesome, just take into account the context of KVO, more info: [link](http://stackoverflow.com/questions/11916502/importance-of-context-parameter-in-key-value-observing) – Flores Robles Mar 08 '14 at 01:15
  • This is good, but for me it seems to appear at the bottom of the table, then jerk down after a split second. – Matt Rowles Aug 07 '14 at 04:30
  • I have an issue implementing this in Xcode 6.4. It seems to work when I scroll but if I remove an item or add an item it goes to the bottom of the list, not stuck to the bottom of the view. Any chance you could help me out? The only thing I couldn't implement from this code is the KVO, would that cause this to not function properly? – Peter Nov 20 '15 at 14:41
10
  1. Add your view to the superview of the table view (if possible; UITableViewControllermakes this impossible).

  2. Add your view to the table view and reposition it in the -scrollViewDidScroll:delegate method (UITableViewDelegateis a sub-protocol of UIScrollViewDelegate).

Daniel
  • 23,129
  • 12
  • 109
  • 154
Martin Ullrich
  • 94,744
  • 25
  • 252
  • 217
  • i tried this -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ CGSize adSize = [awView actualAdSize]; CGRect newFrame = awView.frame; newFrame.origin.x = (self.view.bounds.size.width - adSize.width)/2; newFrame.origin.y = (self.view.bounds.size.height - adSize.height/2) -21; awView.frame = newFrame; } but it's not working at all – Mohamed Emad Hegab Sep 24 '11 at 08:38
  • 2
    don't use self.view.bounds! adjust only the origin.y-value to self.tableView.contentOffset.y – Martin Ullrich Sep 24 '11 at 08:40
  • or add it to your calculation above if you want to keep it centered (but still use self.tableview.bounds.size.height for center calculation) – Martin Ullrich Sep 24 '11 at 08:43
  • You don't need to add as a view to the superview. You can add as a subview to the table view but you'll need to provide a content inset to avoid hiding any content by the "floating" view. – Daniel Aug 18 '13 at 13:04
  • 1
    Daniel's answer below is much better. – Rog Jul 23 '14 at 14:19
4

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]; 
}
Salman Hasrat Khan
  • 1,971
  • 1
  • 20
  • 27
2

For people like me looking for a simple solution using Swift, these answers are kind of outdated. Here's what I did (assuming myCustomView was established somewhere else in the file):

func scrollViewDidScroll(_ scrollView: UIScrollView) {
   
    let pixelsFromBottom = CGFloat(20)//or whatever the
    let theHeight = self.tableView.frame.height + scrollView.contentOffset.y
    myCustomView.frame = CGRect(x: 0, y: theHeight - pixelsFromBottom , width: self.view.frame.width, height: myCustomView.frame.height)

}
Iziah Reid
  • 36
  • 2
0
- (void)viewDidLoad
{
    [super viewDidLoad];

    footerView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT-64, SCREEN_WIDTH, 64)];
    footerView.backgroundColor = [UIColor blueColor ];
    [self.navigationController.view addSubview:footerView];
}   

- (void)dealloc
{
    [footerView removeFromSuperview];
}
stack Stevn
  • 114
  • 6