Instagram-like navigation bar (iOS 7)

2019-02-01 02:48发布

I'm trying to make same affect, as instagram has in their header. How can I do this?

I tried a lot of solutions.

Best - https://github.com/andreamazz/AMScrollingNavbar

But it has one big problem - it's moving bar using uipangesturerecognizer. It's bad for me, because I want to show bar, if table is at the top.

I tried to change work of this control to scroll view delegate, but found a lot of problems with it, have you any ideas, how they made this?

instagram main screen

4条回答
Anthone
2楼-- · 2019-02-01 03:25

Use AMScrollingNavbar with your tableViewController and override the willDisplayCell method to show the bar if table is scrolled to top:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
        [self showNavbar];
    }
}
查看更多
叼着烟拽天下
3楼-- · 2019-02-01 03:39

Using that library, add this to your view controller:

- (BOOL)scrollViewShouldScrollToTop {
    [self showNavbar];
    return YES;
}
查看更多
冷血范
4楼-- · 2019-02-01 03:44

I found THE solution, just like you said - you have to mess around with the scroll view delegate a little bit, but after some 2 hours I had it all figured out. The problem i was trying to solve was to be able to get the header out in one continuous motion just like you do in Instagram.

So, first check out the xib setup, it has a header view at (0 20, 320 85), which is right behind a table view at (0 20, 320 548)

xib setup

So here is what it looks like after launch (table view frame in yellow): after launch

This is what i want it to look like after pulling down (header frame in red): after pulling down

So I'll just paste the code with comments, i hope its understandable enough.

Make a define

#define SIGNIFICANT_SCROLLING_DISTANCE 200

Create two properties

@property (nonatomic) CGFloat lastScrollViewOffsetY;
@property (nonatomic) CGFloat distancePulledDownwards;

Than add the following implementation for scrollViewDidScroll delegate method

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // store current scroll view frame as we will change it later on and set it
    // back to the scroll view in the very end
    CGRect currentScrollViewRect = scrollView.frame;
    // same with the content offset
    CGPoint currentScrollViewOffset = scrollView.contentOffset;
    CGFloat offsetShiftY = self.lastScrollViewOffsetY - scrollView.contentOffset.y;

    if (offsetShiftY > 0) {
        // pulling downwards
        // keep trrack of the distance that we pulled downwards
        self.distancePulledDownwards += offsetShiftY;

        // header opens (table view shifts its frame down) in two cases:
        // 1. contentOffset.y<0
        // 2. scrolled downwards a significant amount or header is already open
        // but in both cases we have to make sure that it doesn't open further than we want it to
        CGFloat wantedOriginY = currentScrollViewRect.origin.y;
        if ((scrollView.contentOffset.y<0) || (self.distancePulledDownwards > SIGNIFICANT_SCROLLING_DISTANCE) || (currentScrollViewRect.origin.y>20)){

            // shift scroll views frame by offset shift
            wantedOriginY = currentScrollViewRect.origin.y + offsetShiftY;
            // compensate that shift by moving content offset back
            currentScrollViewOffset.y += (wantedOriginY <= 105) ? offsetShiftY : 0;
        }
        currentScrollViewRect.origin.y = (wantedOriginY <= 105) ? wantedOriginY : 105;

    }
    else {
        // pulling upwards
        self.distancePulledDownwards = 0;

        // header closes (table view shifts its frame up) in one case: when it is open =) (and contentOffset.y>0 to eliminate closing on bounce)
        if (scrollView.contentOffset.y > 0) {
            CGFloat wantedOriginY = currentScrollViewRect.origin.y + offsetShiftY;
            currentScrollViewRect.origin.y = (wantedOriginY >= 20) ? wantedOriginY : 20;
            currentScrollViewOffset.y += (wantedOriginY >= 20) ? offsetShiftY : 0;
        }
    }

    // set the changed (if it was changed at all) frame to the scroll view
    [scrollView setFrame:currentScrollViewRect];

    // correct offset using a special trick
    // it ensures that scrollViewDidScroll: won't be called on setting the offset
    scrollView.delegate = nil;
    [scrollView setContentOffset:currentScrollViewOffset];
    scrollView.delegate = self;

    // and finally remember the current offset as the last
    self.lastScrollViewOffsetY = scrollView.contentOffset.y;
}

And enjoy your smooth table scrolling back and forth on the screen =) This can also be modified, you can add and resize a header so that it is basically identical to the Instagram one.

查看更多
萌系小妹纸
5楼-- · 2019-02-01 03:46

You can use the below mentioned method in your class in which you want to add effect on navigation bar as there in Instagram.

- (void)scrollViewDidScroll:(UIScrollView *)sender {
//Initializing the views and the new frame sizes.
UINavigationBar *navbar =self.navigationController.navigationBar;
UIView *tableView = self.view;
CGRect navBarFrame = self.navigationController.navigationBar.frame;

CGRect tableFrame = self.view.frame;

//changing the origin.y based on the current scroll view.
//Adding +20 for the Status Bar since the offset is tied into that.

if (isiOS7) {
     navBarFrame.origin.y = MIN(0, MAX(-44, (sender.contentOffset.y * -1)))  +20 ;
     tableFrame.origin.y = navBarFrame.origin.y + navBarFrame.size.height;
}else{
    navBarFrame.origin.y = MIN(0, (sender.contentOffset.y * -1)) +20;
    tableFrame.origin.y = MIN(0,MAX(-44,(sender.contentOffset.y * -1))) ;
}

navbar.frame = navBarFrame;
tableView.frame = tableFrame;

}

查看更多
登录 后发表回答