在导航栏上添加分段控件,并使标题与按钮一起显示

32

我想在导航栏中添加分段控件,同时保留标题和按钮,就像iOS 7应用商店购买部分的例子所示。 (例子)

我尝试将分段控件作为标题视图添加,然后使用提示作为标题,但按钮与分段控件处于同一级别。


正如我所写的,我尝试将分段控件添加为标题视图,并使用导航栏提示设置标题,但是按钮位置偏移了。 - sangi93
8个回答

15

我找到了两个解决方案:

1)如 neural5torm 建议的那样,您可以将分段控件添加到具有与导航栏相同背景颜色的 UIView 中

您可以通过以下方式删除 UINavigationBar 的 hairline:

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

对于非透明的导航栏,这是可以的。



如果您想要一个透明的导航栏:
2)通过重写sizeThatFits来创建一个更高的导航栏的子类UINavigationBar。

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


使用自定义导航栏:

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


标题和按钮项将位于底部。在自定义导航栏的init或通过外观代理调整它们的垂直位置。


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

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

请查看UIBarButtonItem类的参考文档,其中还有setTitlePositionAdjustment等方法用于返回按钮。


创建分段控件时,请将其添加到导航栏中。

[self.navigationController.navigationBar addSubview:segmentedControl];


分段控件将位于顶部。通过在自定义导航栏中重写didAddSubview来调整其垂直位置。

- (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;
    }
}

1
我按照您的指示成功将任何视图添加到导航栏中,但不幸的是,我无法与/点击任何子视图进行交互。我正在UITableViewController上执行此操作。 - Fouad

14

我尝试了另一种方法来解决你的问题,因为仅使用导航栏似乎不起作用(也许是因为AppStore应用程序使用了私有API,但我不够熟练,无法确定...)

无论如何,我只是在导航栏下方放置了一个工具栏,在其中添加了一个分段控件,全部放在普通的UIViewController中。

这是在Storyboard中的样子:

Storyboard

这是在模拟器中的结果:

Simulator

请注意将表视图向下偏移以占用工具栏使用的垂直空间。希望这可以帮助你!


6
我之前考虑过这个问题,我对这种方法唯一的疑虑是导航栏和分段控件之间的水平接缝。 - sangi93
确实,这是主要问题。如果您有更好的解决方案,请分享您的发现并创建一个答案。谢谢。 - neural5torm
我用一个hack来隐藏背景的子视图并构建一个自定义视图作为更高的导航栏,以使单元格对齐到顶部。我不知道需要向子视图添加什么约束,但也可以通过这种方式完成,并从我的实现中删除嵌套的导航栏。 - cynistersix

9
您可以在苹果示例代码中找到使用UISegmentedControl的导航栏:https://developer.apple.com/library/ios/samplecode/NavBar/Introduction/Intro.html 以下是我对此代码的解释(以编程方式创建):
// 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

当分段控件显示三个不同的视图控制器时,它是如何工作的? - koen
1
在这段代码中,我们不会展示不同的视图控制器:当您在分段控件中选择另一个项目时,我们只是更改_table内容。 - pigmasha
是的,那很有道理。巧合的是,我实际上在一个小时前发布了一个关于我的问题的问题:http://stackoverflow.com/questions/31761396/uinavigationbar-with-uisegmentedcontrol-partially-covers-childviews - koen
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - davew

8
您可以使用导航项`Prompt`属性来实现这个功能。只需要在Storyboard中设置该属性,导航栏就会自动漂亮地淡入淡出。唯一的缺点是文本有点小。
如下图所示:

enter image description here


2

尝试创建一个UINavigationBar子类,并使其符合UIToolbarDelegate协议。然后在-init方法中创建你的分段控制器,将其添加到UIToolbar上,并将其委托给你自定义的UINavigationBar类。然后写下这个魔法:

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

祝你好运!


你能详细说明一下吗?你是在建议创建一个 UIToolbar,将其作为 UINavigationBar 的子视图,并将 UISegmentedControl 添加到工具栏中吗?如果不是,那么工具栏应该添加在哪里? - Jordan H

2

我尝试在Xamarin.iOS中实现此功能。从iOS 6开始,您可以继承UINavigationBar并在需要的位置添加控件和按钮。


1
我的解决方案是这样的:
将工具栏和分段控件添加到您的xib文件中。 按照您的需要进行自定义,并将其连接到视图控制器的出口:

enter image description here

然后,将这个代码放到viewDidLoad方法中:
- (void)viewDidLoad
{
    [super viewDidLoad];

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

    self.navigationItem.rightBarButtonItem = item;
}

enter image description here


0
我还没有完全实现它,但以下是我的计划。(ios7) 这将用于使标题和按钮在同一导航栏旁边。
在storyboard中,向导航栏添加一个空视图。然后在该视图中添加标签和分段控件。这样可以将任何控件添加到导航栏。到目前为止,UI可以工作,只是还没有连接好。只是想分享我迄今为止发现的东西。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接