I have a UIView with height of 100 pixels that's on top of my UITableView. When I scroll up I want the UIView to scroll together with my UITableView as if it's part it. When 50 pixels of my UIView is hidden from scrolling up, I want to pin the UIView at the top while I continue scrolling up. How can this be achieved? I tried using changing my UIView's top NSLayoutConstraint constant equal to my tableview's content offset, but they don't scroll at the same speed.
-
You should take a look to this answer: http://stackoverflow.com/a/17583567/6203030 what you are looking for is the style of the tableView – Aitor Pagán Apr 04 '17 at 16:23
4 Answers
First make sure your tableView is grouped
:
self.tableView = UITableView(frame: CGRect(x: 0, y: (self.navigationController?.navigationBar.frame.maxY)!, width: self.view.bounds.size.width, height: (self.view.bounds.size.height - (self.navigationController?.navigationBar.frame.maxY)!)), style: .grouped)
self.tableView.delegate = self
self.tableView.dataSource = self
self.view.addSubview(self.tableView)
Then you need to add the UIView
into the subview
of your tableView
:
self.myView = UIView()
self.myView.backgroundColor = UIColor.green
self.myView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 100)
self.tableView.addSubview(self.myView)
Add a header of height 100 for your tableView's first section so that your cells are at right place:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100
}
Then adjust the frame of your UIView
when scrolling:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset.y
if(offset > 50){
self.myView.frame = CGRect(x: 0, y: offset - 50, width: self.view.bounds.size.width, height: 100)
}else{
self.myView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 100)
}
}
Demo:

- 1,277
- 9
- 22
-
1This is a fantastic way to do this and the best answer I have found for it. This should be the accepted answer. – msweet168 Mar 19 '19 at 20:39
If I understand you'r question correctly, You can do it by implementing table view scrollViewDidScroll:
method like this
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
static CGFloat previousOffset;
CGRect rect = self.yourUIView.frame;
//NSLog you'r UIView position before putting any condition
// NSLog(@"Origin %f",rect.origin.y);
rect.origin.y += previousOffset - scrollView.contentOffset.y;
previousOffset = scrollView.contentOffset.y;
//assuming you'r UIView y position starts from 0
//Before setting the condition please make sure to run without any
//condition if not working
if(rect.origin.y>=-50 && rect.origin.y<=0){
self.yourUIView.frame = rect;
}
}
Hope it helps...

- 196
- 1
- 8
What you need is to implement the viewForHeader inSection
method for your tableView (remember to make your ViewController implementing the tableviewDelegate protocol) and once you've got it you should set your tableViewStyle to UITableViewStylePlain
Share your code if you are interested in more help.

- 1
- 1

- 423
- 7
- 18
I got the same problem with
navigationItem.largeTitleDisplayMode = .always
navigationBar.prefersLargeTitles = true
and
tableView.contentInset = UIEdgeInsets(top: 40, left: 0, bottom: 0, right: 0)
For me nothing from any above options can help but I realised that you can just call
tableView.setContentOffset(CGPoint(x: 0, y: -tableView.contentInset.top), animated: false)
in viewDidload()
and problem gone! :)
Totally forgot about this method and spent too much time for this creepy behavior.
Good Luck!

- 621
- 8
- 12