Add segmented control to navigation bar and keep t

2019-01-13 00:10发布

问题:

I want to add segmented control to the navigation bar but also keep the title and buttons, like in iOS 7 Appstore purchased section (example)

I have tried adding segmented control as title view and then using prompt as the title, but then the buttons are on the same level as segmented control.

回答1:

I have tried solving your problem using another approach since using a navigation bar only didn't seem to work out (maybe it's because the AppStore app is using a private api but I'm not knowledgeable enough to tell for sure...) Anyway I simply used a toolbar placed just underneath the navigation bar on which I added a segmented control, all inside a regular UIViewController.

This is what it looks like in Storyboard:

And this is the result in Simulator:

Just be careful to offset the table view down to account for the vertical space used up by the toolbar. Hope this helps!



回答2:

I found two solutions:

1) As suggested by neural5torm, you can add the segmented control to an UIView with the same background color of the navigation bar

You can remove UINavigationBar's hairline in this way:

for (UIView *view in self.navigationController.navigationBar.subviews)
{
    for (UIView *view2 in view.subviews)
    {
        if ([view2 isKindOfClass:[UIImageView class]])
        {
            [view2 removeFromSuperview];
        }
    }
}

This is ok for not translucent navigation bar.



If you want a translucent navigation bar:
2) Subclass UINavigationBar to create a taller bar by overriding sizeThatFits

- (CGSize)sizeThatFits:(CGSize)size
{
    size.width = self.frame.size.width;
    size.height = your height (probably 88.0f);
    return size;
}


To use your custom navigation bar:

UINavigationController *navController = [[UINavigationController alloc] initWithNavigationBarClass:[YouNavigationBar class] toolbarClass:nil];
[navController setViewControllers:@[viewController]];


Title and button items will be at the bottom. Adjust their vertical positions (in the init of your custom navigation bar or via appearance proxy)

// Title view
[self setTitleVerticalPositionAdjustment:-dy forBarMetrics:UIBarMetricsDefault];

// Button item as icon/image 
[[UIBarButtonItem appearanceWhenContainedIn:[YourCustomNavigationBar class], nil] setBackgroundVerticalPositionAdjustment:-dy forBarMetrics:UIBarMetricsDefault];

Look at the UIBarButtonItem class reference, there are also setTitlePositionAdjustment and other methods for back button


When you create your segmented control, add it to the navigation bar

[self.navigationController.navigationBar addSubview:segmentedControl];


The segmented control will be at the top. Adjust its vertical position by overriding didAddSubview in your custom navigation bar

- (void)didAddSubview:(UIView *)subview
{
    [super didAddSubview:subview];

    if ([subview isKindOfClass:[UISegmentedControl class]])
    {
        CGRect frame = subview.frame;
        frame.origin.y += your extra height (probably 44.0f);
        subview.frame = frame;
    }
}


回答3:

You can find navigation bar with UISegmentedControl in Apple Sample Code: https://developer.apple.com/library/ios/samplecode/NavBar/Introduction/Intro.html

Here is my interpretation of this code (create programmatically):

// File MySegmController.h
@interface MySegmController : UIViewController
@end

// File MySegmController.m
#import "MySegmController.h"

@interface MyNavBarView : UIView
@end

@interface MySegmController ()<UITableViewDataSource, UITableViewDelegate>
{
    UISegmentedControl* _segm;
    UITableView* _table;
}
@end

#define SEGM_WIDTH 250

@implementation MySegmController

- (void)loadView
{
    [super loadView];
    self.view.backgroundColor = [UIColor whiteColor];
    self.title = @"Title";

    float w = self.view.bounds.size.width;

    NSArray* items = [[NSArray alloc] initWithObjects: @"One", @"Two", @"Three", nil];
    _segm = [[UISegmentedControl alloc] initWithItems: items];
    [items release];
    [_segm sizeToFit];
    _segm.frame = CGRectMake((w - SEGM_WIDTH) / 2, 0, SEGM_WIDTH, _segm.bounds.size.height);
    _segm.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
    _segm.selectedSegmentIndex = 0;

    MyNavBarView* topView = [[MyNavBarView alloc] initWithFrame: CGRectMake(0, 0, w, _segm.bounds.size.height + 10)];
    topView.backgroundColor = [UIColor whiteColor];
    topView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [topView addSubview: _segm];
    [_segm release];

    _table = [[UITableView alloc] initWithFrame: CGRectMake(0, topView.bounds.size.height, w, self.view.bounds.size.height - topView.bounds.size.height) style: UITableViewStylePlain];
    _table.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    _table.dataSource = self;
    _table.delegate = self;
    [self.view addSubview: _table];
    [_table release];

    // add topView AFTER _table because topView have a shadow
    [self.view addSubview: topView];
    [topView release];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.navigationController.navigationBar.translucent = NO;
    // pixel_transp.png - 1x1 image with transparent background
    self.navigationController.navigationBar.shadowImage = [UIImage imageNamed: @"pixel_transp"];
    // pixel.png - 1x1 image with white background
    [self.navigationController.navigationBar setBackgroundImage: [UIImage imageNamed: @"pixel"] forBarMetrics: UIBarMetricsDefault];

    UIBarButtonItem* bt = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemCancel target: self action: @selector(onCancel)];
    self.navigationItem.rightBarButtonItem = bt;
    [bt release];
}

- (void)onCancel
{
    [self.presentingViewController dismissViewControllerAnimated: YES completion: NULL];
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier: @"MyId"];
    if (!cell) cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: @"MyId"] autorelease];
    cell.textLabel.text = @"text";
    return cell;
}

@end

@implementation MyNavBarView

- (void)willMoveToWindow: (UIWindow *)newWindow
{
    self.layer.shadowOffset = CGSizeMake(0, 1.0f / UIScreen.mainScreen.scale);
    self.layer.shadowRadius = 0;
    self.layer.shadowColor = [UIColor blackColor].CGColor;
    self.layer.shadowOpacity = 0.25f;
}

@end


回答4:

You could use navigation item Prompt property for this. Just set the property in storyboard like this and the navigation bar will automatically fade up and down nicely. Only downside is the text is kinda small.



回答5:

I tried to do it in Xamarin.iOS, from iOS 6, you can inherit UINavigationBar and add controls, button where you want.



回答6:

Try to create UINavigationBar subclass and let it conform to UIToolbarDelegate protocol. Then in -init method create your segment control, add it on UIToolBar and set its delegate to your custom UINavigationBar class. Then write this magic:

- (UIBarPosition)positionForBar:(id <UIBarPositioning>)bar {
    return UIBarPositionTopAttached;
}

Good luck!



回答7:

I haven't fully implemented it but the following is what I plan to do. (ios7) This would be for having title and the buttons on the same nav bar side by side.

In storyboard, add a blank view to the navigation bar. Then add a label and a segmented control to that view. This allows you to add any control you want to the nav bar. So far the UI works, just haven't wired it up. Just wanted to share what I have found so far.



回答8:

My solution was this:
Add Toolbar and Segmented control to your xib file. Customize it as you need and connect it to an outlet of your view controller:

Then, put this in the viewDidLoad method:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // add after your setup code
    UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:self.segmentedControl];

    self.navigationItem.rightBarButtonItem = item;
}