Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS —Sticky segmented control like App Store app

I am creating an app and in one of the navigation views, I have a very similar design as that of the App Store app — see Details | Reviews | Related section. Following on similar lines, I wish to implement the segmented control in the 'same' way Apple has done in their app. (This is also similar to what Apple does in the Artist -> Albums navigation view in the default iOS 7 music app, albeit for a table header (maybe).)

  • If you scroll up, when the segmented control container touches the navigation bar, it sticks there.
  • It also allows the user to notice that this is some kind of overlay due to the alpha associated with it.
  • When you scroll down, it moves into position when required.

What I have done —

I have created a container view with the segmented control. When the scrollView scrolls, I reposition my container view to accomplish the sticky effect. This is just pseudo-code but my code actually works.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView == self.labTestScrollView)
    {
        /*
         As soon as the user scrolls up, y changes, therefore, we need to stick the options container view
         such that it doesn't go past the UINavigationBar
         Need to check if the origin of the options container view in the coordinate system of the main
         superview is just gone past the UINavigationBar in this controller's view.
         - get the bounds rect for the options container view
         - convert these bounds and position them in the coordinates of this controller's view
         - check if origin.x for container view is less than that of view.origin.y
         - if less than stick it by converting the headerFrame to the coordinate system of the options 
         container view; and raise the stuck flag
         - if greater, check if the stuck flag is raised; check for another object in space before the container view and adjust accordingly.
         */
    }
}

There are two issues:

  1. No overlay effect. I can configure the alpha such that the effect is a bit more visible but that doesn't seem natural.
  2. The second concern stems from the first. This seems like a very specific solution. I am looking forward to something that's more natural; and something that could work by default using table views or something.
like image 237
p0lAris Avatar asked Dec 09 '22 12:12

p0lAris


1 Answers

Why not simply use a UITableView?

Put your 'top content' in section 0 and have no header for that section. Put all the other stuff in section 1 and give that section a header with your UISegmentedControl.

Following code works pretty well. You might want to find a way to give the background of the header a 'blur' effect to mimic Apple's behavior some more; maybe GPUimage could help you there?

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return section == 0 ? 1 : 5;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *identifier = indexPath.section == 0 ? @"header" : @"content";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    // customize cell
    return cell;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if(section == 1) {
        UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"Foo", @"Bar"]];
        segmentedControl.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.95];
        return segmentedControl;
    }
    return nil;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return section == 0 ? 0 : 44;
}

I'll leave the tweaking up to you ;)

like image 65
fguchelaar Avatar answered Dec 11 '22 09:12

fguchelaar