Question

I would like to create a UI where there's a nav bar and its buttons, with a toolbar underneath that, both always visible. I would then like a toolbar at the bottom that will replace the content visible in the middle of the screen when you tap a button. I would use a UITabBarController but I don't want a text label underneath nor an image for the icon - the buttons will be a unicode character. They should be gray then filled in with the tint color when one is selected. I was thinking the way to do this would be to apply a tint when the button is tapped, but since there is no sticky "selected state" for a bar button I'm not sure how to do that.

I'm also not sure how to replace the content in the middle. I was thinking I should create a container, then just make an action method from each button that will performSegueWithIdentifier to a different container that will contain the different content. But only one view controller can be embedded - I can't create multiple segues from the container. I'm basically trying to simulate a tab bar controller with smaller buttons, no label, and not the entire content on screen gets replaced upon tapping a button.

How would I go about doing this? I'd like to get the basic layout done in Interface Builder but of course will need some code. Thanks!

This is basically what I'd like to achieve: enter image description here

Was it helpful?

Solution 2

I've implemented my desired behavior.

It's not a particularly clean solution but it does offer an added benefit: the ability to swipe between the tabs at the bottom.

Essentially:

  1. I created a Container View that fills the entire screen, which contains a Page View Controller
  2. I removed the Page Control (didn't implement delegate methods so you cannot see the dots)
  3. The pages are 5 Collection Views from a reusable View Controller
  4. I implemented the delegate method that's called when a page fully transitions and then at that point I change the tint color of the appropriate bar button at the bottom (defaulted to gray), after looping through the others to reset the tint to gray.
  5. If the user taps a bar button instead of swiping, I set the view controllers for the page view controller and then update the tints.

This is working well, the code isn't very nice though.

One other thing I may do is override the bar button highlight state.
Tab bar buttons shouldn't become lighter when the user highlights one.

Interestingly enough, it's quite easy to not allow swiping between the pages, simply by removing the Page View Controller Data Source methods. Then it behaves like a true tabbed interface. I quite like the flexibility of having both swiping and tapping available though.

OTHER TIPS

This is the way I've done this in the past. The code is in a custom container controller, which is the controller that's embedded in the container view in the storyboard. So, in viewDidAppear:, I add the first controller as a child, and on a button click, I call switchToNewView:.

@implementation ContainerController


- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIViewController *initial = [self.storyboard instantiateViewControllerWithIdentifier:@"InitialVC"];
    [self addChildViewController:initial];
    [self.view addSubview:initial.view];
    self.currentController = initial;
    [self constrainViewEqual:self.currentController];
}

-(IBAction)switchToNewView {
    UIViewController *sub = [self.storyboard instantiateViewControllerWithIdentifier:@"SubstituteVC"];
    [self addChildViewController:sub];
    sub.view.frame = self.view.bounds;
    [self moveToNewController:sub];
}

-(void)moveToNewController:(UIViewController *) newController {
    [self.currentController willMoveToParentViewController:nil];
    [self transitionFromViewController:self.currentController toViewController:newController duration:.6 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{}
         completion:^(BOOL finished) {
             [self.currentController removeFromParentViewController];
             [newController didMoveToParentViewController:self];
             self.currentController = newController;
             [self constrainViewEqual:self.currentController];
         }];
}

constrainViewEqual is a category method I have for adding constraints to the controller's view. It looks like this,

-(void)constrainViewEqual:(UIViewController *) vc {
    [vc.view setTranslatesAutoresizingMaskIntoConstraints:NO];
    NSLayoutConstraint *con1 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:vc.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
    NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:vc.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
    NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeWidth relatedBy:0 toItem:vc.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
    NSLayoutConstraint *con4 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:0 toItem:vc.view attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
    NSArray *constraints = @[con1,con2,con3,con4];
    [self.view addConstraints:constraints];
}

This is not a complete answer, just a bit I can help with currently


You can use a UIButton as a customView for the UIBarButtonItem object and then utilize the UIButton object's highlighted and/or selected state.
Also... if you're planning to use Unicode instead of images, then the tintColor won't really matter.
You might as well simply change the textColor of the button titleLabel (depending on the UIControlStateNormal)

Example:

- (void)testMethod
{    
    UIToolbar *tbTest = [[UIToolbar alloc] init];
    [tbTest setFrame:CGRectMake(0, 100, 320, 44)];
    [self.view addSubview:tbTest];

    UIButton *btnTest = [UIButton buttonWithType:UIButtonTypeSystem];
    [btnTest setFrame:CGRectMake(0, 0, 100, 44)];
    [btnTest setTintColor:[UIColor blueColor]];

    [btnTest setTitle:@"Normal" forState:UIControlStateNormal];
    [btnTest setTitleColor:[UIColor redColor] forState:UIControlStateNormal];

    [btnTest setTitle:@"Highlighted" forState:UIControlStateHighlighted];
    [btnTest setTitleColor:[UIColor orangeColor] forState:UIControlStateHighlighted];

    [btnTest setTitle:@"Selected" forState:UIControlStateSelected];
    [btnTest setTitleColor:[UIColor purpleColor] forState:UIControlStateSelected];

    [btnTest addTarget:self action:@selector(doSomething:) forControlEvents:UIControlEventTouchUpInside];

    UIBarButtonItem *btn2Test = [[UIBarButtonItem alloc] initWithCustomView:btnTest];

    [tbTest setItems:@[btn2Test]];
}

-(void)doSomething:(UIButton *)sender
{
    [sender setSelected:!sender.selected];
}

Regarding recreating the tabBar, i can only think of this way:

  1. Pin a UITabBar-like view to the bottom
  2. Fill up the top space with an empty UIView object
  3. Add the tab viewControllers as childViewControllers to this UIView

Furthermore, you can look into a somewhat-similar component I just recently started authoring on github:
https://github.com/staticVoidMan/SVMSlidingTabBar
1. Non-storyboard (but not too difficult to port)
2. Supports only images for the tab buttons right now (but thanks for the idea)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top