How to put buttons over UITableView which won't scroll with table in iOS

IosObjective CUitableview

Ios Problem Overview


I want to put buttons over UITableView which stays on same position of screen, won't scroll with UITableView. When I tried to addSubview buttons, they are displayed but scrolls with UITableView.

Reason to put buttons over UITableView is to let user operate some action on it. I'm not talking about having buttons in cell. They are floating buttons which never moves their position.

I'm using UITableViewController, and I don't want to use header or footer for this purpose. And also another some bar (UIToolbar for instance) is not an option for me.

Thanks in advance.

Ios Solutions


Solution 1 - Ios

You can do it also with UITableViewController (no need for ordinary UIViewController, which nests your table or VC)

UPDATED iOS11+ using SafeAreas

you want to use autolayout to keep the view on bottom

{
    [self.view addSubview:self.bottomView];
    [self.bottomView setTranslatesAutoresizingMaskIntoConstraints:NO];
    UILayoutGuide * safe = self.view.safeAreaLayoutGuide;
    [NSLayoutConstraint activateConstraints:@[[safe.trailingAnchor constraintEqualToAnchor:self.bottomView.trailingAnchor],
                                              [safe.bottomAnchor constraintEqualToAnchor:self.bottomView.bottomAnchor],
                                              [safe.leadingAnchor constraintEqualToAnchor:self.bottomView.leadingAnchor]]];
    [self.view layoutIfNeeded];
}

and to make sure view is always on top

- (void)viewDidLayoutSubviews {
    
    [super viewDidLayoutSubviews];
    
    [self.view bringSubviewToFront:self.bottomView];
    
}

THE PREVIOUS OLD SOLUTION

By scrolling the table, you need to adjust the position of the "floating" view and it will be fine

If you are in a UITableViewController, just

If you want to float the view at the top of the UITableView

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGRect frame = self.floatingView.frame;
    frame.origin.y = scrollView.contentOffset.y;
    self.floatingView.frame = frame;
    
    [self.view bringSubviewToFront:self.floatingView];
}

If you want float the view on the bottom of the UITableView

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGRect frame = self.floatingView.frame;
    frame.origin.y = scrollView.contentOffset.y + self.tableView.frame.size.height - self.floatingView.frame.size.height;
    self.floatingView.frame = frame;
    
    [self.view bringSubviewToFront:self.floatingView];
}

I believe thats the real answer to your question

Solution 2 - Ios

In case you are using navigation controller you can add the view to it:

[self.navigationController.view addSubview:yourView];

Example:

UIButton *goToTopButton = [UIButton buttonWithType:UIButtonTypeCustom];
goToTopButton.frame = CGRectMake(130, 70, 60, 20);
[goToTopButton setTitle:@"Scroll to top" forState:UIControlStateNormal];
[goToTopButton addTarget:self action:@selector(goToTop) forControlEvents:UIControlEventTouchUpInside];
[goToTopButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[goToTopButton.layer setBorderColor:[[UIColor whiteColor] CGColor]];
goToTopButton.titleLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:13];
[self.navigationController.view goToTopButton];

Solution 3 - Ios

If you want to show a static control view covering a table view, you have three options:

  1. Don't use UITableViewController. Instead create a UIViewController with a UITableView subview and put your Table View delegate/datasource code in the UIViewController. This option may or may not work depending on the architecture of your app. For example, if you're trying to implement a subclass a UITableViewController with a lot of custom logic, this isn't ideal.

  2. The WWDC 2011 method. See the WWDC 2011 Session 125 "UITableView Changes, Tips & Tricks" starting at 32:20. This method of adjusting the placement of the view whenever the table view scrolls was recommended by Apple before AutoLayout was introduced to iOS and before we had so many different screen sizes to deal with. I don't recommend it since you'll be managing positions for all the different screen sizes yourself.

  3. I recommend using a UIViewController with a container view that will contain your UITableViewController. This way, you can keep the table view logic separate in the UITableViewController. The UIViewController hosts a 'dumb' container for the UITableViewController and it also holds the static control view. To do this, drag a UIViewController to your storyboard and drag a "Container View" inside it. Delete the UIViewController that comes automatically attached to the container view, and then attach your table view controller to be displayed in the container view by control dragging from the contrainer view to the table view controller and selecting "embed". Now, you can add static controls as subviews to the UIViewController that will be displayed on top of the table view. It will look something like this:

Storyboard For a UITableViewController inside a container view

I prefer this method because UIViewController can handle the control logic and the UITableViewController handles the table view logic. Some other answers here recommend adding the static control as a subview to a Navigation Controller or Window. These only work as long as you never add another view controller to the navigation controller or window.

Solution 4 - Ios

One solution to this is to extend UIViewController instead of UITableViewController. You will need to add your own table view and set everything up. Then you can add your button's to the view controller's view instead of the table view.

Solution 5 - Ios

For swift :

override func scrollViewDidScroll(scrollView: UIScrollView){
    var frame: CGRect = self.floatingView.frame
    frame.origin.y = scrollView.contentOffset.y
    floatingView.frame = frame
    
    view.bringSubviewToFront(floatingView)
}

This function is called every time you scroll. Then inside you get the frame of your UIView and update its position depending on how much you scrolled. Your UIView is constantly moving with your UIScrollView so to the user it looks like its floating.

Solution 6 - Ios

you can add buttons on UIWindow no need to extend it to UIViewController instead of UITableviewController.Just add buttons on window.

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIButton *btn =[UIButton buttonWithType:UIButtonTypeCustom];
[btn setFrame:CGRectMake(60, 200,40, 60)];
[btn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
[window addSubview:btn];

Solution 7 - Ios

I've create a library in order to make it easier to add a floating button on top of a UITableView/UICollectionView/UIScrollView. Is called MEVFloatingButton.

These are the steps for use it.

1- Import category file

#import "UIScrollView+FloatingButton.h"

2 - Add delegate and the optional delegate methods.

  @interface ViewController () <MEVFloatingButtonDelegate>

  #pragma mark - MEScrollToTopDelegate Methods

  - (void)floatingButton:(UIScrollView *)scrollView didTapButton:(UIButton *)button;

2 - Create a MEVFloatingButtonobject.

MEVFloatingButton *button = [[MEVFloatingButton alloc] init];
button.animationType = MEVFloatingButtonAnimationFromBottom;
button.displayMode = MEVFloatingButtonDisplayModeWhenScrolling;
button.position = MEVFloatingButtonPositionBottomCenter;
button.image = [UIImage imageNamed:@"Icon0"];
button.imageColor = [UIColor groupTableViewBackgroundColor];
button.backgroundColor = [UIColor darkGrayColor];
button.outlineColor = [UIColor darkGrayColor];
button.outlineWidth = 0.0f;
button.imagePadding = 20.0f;
button.horizontalOffset = 20.0f;
button.verticalOffset = -30.0f;
button.rounded = YES;
button.hideWhenScrollToTop = YES;

4 - Assigned the button and delegate to the UITableView.

[self.tableView setFloatingButtonView:button];
[self.tableView setFloatingButtonDelegate:self]

Demo results

DemoDemoDemo

Solution 8 - Ios

there is a better solution for this. you can do this by disabling the Auto Layout(button.translatesAutoresizingMaskIntoConstraints = false) property of the corresponding Button or any UIView for floating button:

Swift 4

//create a button or any UIView and add to subview
let button=UIButton.init(type: .system)
button.setTitle("NEXT", for: .normal)
button.frame.size = CGSize(width: 100, height: 50)
self.view.addSubview(button)

//set constrains
button.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 11.0, *) {
     button.rightAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
     button.bottomAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
} else {
     button.rightAnchor.constraint(equalTo: tableView.layoutMarginsGuide.rightAnchor, constant: 0).isActive = true
     button.bottomAnchor.constraint(equalTo: tableView.layoutMarginsGuide.bottomAnchor, constant: -10).isActive = true
}

Solution 9 - Ios

I just saw WWDC 2011 TableView,Tips and Tricks videos. Floating views are exactly the same thing.All you have to do is change frame back to original position on scrollViewDidScroll.

https://developer.apple.com/videos/wwdc/2011/

Check videos TableViews tips and tricks.

Solution 10 - Ios

I want my class to be a UITableViewController subclass, and the subview needs to be a regular subview, using auto layout (if I want to).
So, here's what I did:

    private weak var _tableView:UITableView?
    override var tableView: UITableView!{
        get {
            return self._tableView
        }
        set {
            self._tableView = newValue
        }
    }

    override func viewDidLoad() {
        // Re-root
        let tableView = super.tableView! // keep a reference to the original tableview
        self.tableView = tableView
        view = UIView() // Create my own view
        tableView.translatesAutoresizingMaskIntoConstraints = true
        view.addSubview(tableView)
        tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }

You can now add whatever you want to the view of the view controller, while tableView is the original tableview.
I know the question was in Objective C, but the code is fairly simple, and I just copy pasted from my own code.

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
QuestionPlan BView Question on Stackoverflow
Solution 1 - IosPeter LapisuView Answer on Stackoverflow
Solution 2 - IosYossiView Answer on Stackoverflow
Solution 3 - IosGingerBreadManeView Answer on Stackoverflow
Solution 4 - IosrmaddyView Answer on Stackoverflow
Solution 5 - IosEsqarrouthView Answer on Stackoverflow
Solution 6 - IosManiaChampView Answer on Stackoverflow
Solution 7 - IosManuel EscrigView Answer on Stackoverflow
Solution 8 - IosmanuknView Answer on Stackoverflow
Solution 9 - Iosuser1010819View Answer on Stackoverflow
Solution 10 - IosMoshe GottliebView Answer on Stackoverflow