xonegirlz
xonegirlz

Reputation: 8969

make UIView in UIScrollView stick to the top when scrolled up

So in a UITableView when you have sections the section view sticks to the top until the next section overlaps it and then it replaces it on top. I want to have a similar effect, where basically I have a UIView in my UIScrollView, representing the sections UIView and when it hits the top.. I want it to stay in there and not get carried up. How do I do this? I think this needs to be done in either layoutSubviews or scrollViewDidScroll and do a manipulation on the UIVIew..

Upvotes: 18

Views: 21670

Answers (4)

evya
evya

Reputation: 3647

To create UIView in UIScrollView stick to the top when scrolled up do:

func createHeaderView(_ headerView: UIView?) {
    self.headerView = headerView
    headerViewInitialY = self.headerView.frame.origin.y
    scrollView.addSubview(self.headerView)
    scrollView.delegate = self
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let headerFrame = headerView.frame
    headerFrame.origin.y = CGFloat(max(headerViewInitialY, scrollView.contentOffset.y))
    headerView.frame = headerFrame
}

Upvotes: 25

Enrico Susatyo
Enrico Susatyo

Reputation: 19790

Evya's solution works really well, however if you use Auto Layout, you should do something like this (The Auto Layout syntax is written in Masonry, but you get the idea.):

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    //Make the header view sticky to the top.
    [self.headerView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.scrollView.mas_top).with.offset(scrollView.contentOffset.y);
        make.left.equalTo(self.scrollView.mas_left);
        make.right.equalTo(self.scrollView.mas_right);

        make.height.equalTo(@(headerViewHeight));
    }];

    [self.scrollView bringSubviewToFront:self.headerView];
}

Upvotes: 2

Scott Byrns KCL
Scott Byrns KCL

Reputation: 211

Swift Solution based on EVYA's response:

var navigationBarOriginalOffset : CGFloat?

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    navigationBarOriginalOffset = navigationBar.frame.origin.y
}

func scrollViewDidScroll(scrollView: UIScrollView) {
    navigationBar.frame.origin.y = max(navigationBarOriginalOffset!, scrollView.contentOffset.y)
}

Upvotes: 11

isaac
isaac

Reputation: 4897

If I recall correctly, the 2010 WWDC ScrollView presentation discusses precisely how to keep a view in a fixed position while other elements scroll around it. Watch the video and you should have a clear-cut approach to implement.

It's essentially updating frames based on scrollViewDidScroll callbacks (although memory is a bit hazy on the finer points).

Upvotes: 2

Related Questions