【问题标题】:Add segmented control to navigation bar and keep title with buttons向导航栏添加分段控件并使用按钮保留标题
【发布时间】:2017-07-28 10:29:53
【问题描述】:

我想在导航栏上添加分段控件,但也要保留标题和按钮,就像在 iOS 7 Appstore 购买部分中一样 (example)

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

【问题讨论】:

  • 正如我所写,我尝试将分段控件添加为标题视图并使用导航栏提示设置标题,但是按钮随后关闭。

标签: ios uinavigationbar uisegmentedcontrol


【解决方案1】:

我找到了两个解决方案:

1)根据neural5torm的建议,可以将分段控件添加到与导航栏背景颜色相同的UIView中

你可以这样去掉 UINavigationBar 的细线:

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

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



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

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


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

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

【讨论】:

  • 我按照您的说明操作,能够将任何视图添加到导航栏,但不幸的是我无法交互/单击任何子视图。我在 UITableViewController 上做。
【解决方案2】:

我尝试使用另一种方法解决您的问题,因为仅使用导航栏似乎没有解决问题(可能是因为 AppStore 应用程序使用的是私有 api,但我没有足够的知识来确定.. .) 无论如何,我只是使用了一个放置在导航栏下方的工具栏,我在该导航栏上添加了一个分段控件,所有这些都在常规 UIViewController 中。

这就是 Storyboard 中的样子:

这是模拟器中的结果:

请注意将表格视图向下偏移以考虑工具栏使用的垂直空间。 希望这会有所帮助!

【讨论】:

  • 我之前考虑过这个问题,我使用这种方法的唯一问题是导航栏和分段控件之间的水平接缝。
  • 确实,这是主要问题。如果您想出更好的解决方案,请根据您的发现创建答案。谢谢
  • 我用 hack 摆脱了它,隐藏了作为背景的子视图,并在更高的导航栏中构建了一个作为导航栏的自定义视图,以使单元格与最佳。我不知道需要向子视图添加哪些约束,但也可以这样做,并从我的实现中删除嵌套的导航栏。
【解决方案3】:

您可以在 Apple 示例代码中找到带有 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

【讨论】:

  • segmentedControls 显示三个不同的 viewControllers 时这是如何工作的?
  • 我们没有在这段代码中显示不同的viewControllers:当你在segmentedControl中选择另一个项目时,我们只是改变_table的内容
  • 是的,这是有道理的。巧合的是,我实际上在一小时前发布了一个关于我的问题的问题:stackoverflow.com/questions/31761396/…
  • 我见过的所有解决方案都不是特别优雅(包括 Apple 的),但使用 Apple 的方法似乎是最安全的。在 Apple 的示例代码中,我使用了 EnhancedNavBarView 并将标签替换为分段控件。
【解决方案4】:

您可以为此使用导航项 Prompt 属性。只需像这样在情节提要中设置属性,导航栏就会自动淡入淡出。唯一的缺点就是文字有点小。

【讨论】:

    【解决方案5】:

    我尝试在 Xamarin.iOS 中做到这一点,从 iOS 6 开始,您可以继承 UINavigationBar 并添加控件、按钮。

    【讨论】:

      【解决方案6】:

      尝试创建 UINavigationBar 子类,让它符合 UIToolbarDelegate 协议。然后在 -init 方法中创建您的段控件,将其添加到 UIToolBar 并将其委托设置为您的自定义 UINavigationBar 类。然后写这个魔法:

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

      祝你好运!

      【讨论】:

      • 你能扩展一下吗?您是否建议创建UIToolbar,将其作为子视图添加到UINavigationBar,并将UISegmentedControl 添加到工具栏?如果没有,工具栏在哪里添加?
      【解决方案7】:

      我的解决方案是这样的:
      将工具栏和分段控件添加到您的 xib 文件中。 根据需要对其进行自定义并将其连接到视图控制器的插座:

      然后,将其放入viewDidLoad 方法中:

      - (void)viewDidLoad
      {
          [super viewDidLoad];
      
          // add after your setup code
          UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:self.segmentedControl];
      
          self.navigationItem.rightBarButtonItem = item;
      }
      

      【讨论】:

        【解决方案8】:

        我还没有完全实现它,但以下是我计划做的。 (ios7) 这是为了让标题和按钮并排在同一个导航栏上。

        在故事板中,向导航栏添加一个空白视图。然后将标签和分段控件添加到该视图。这允许您将任何您想要的控件添加到导航栏。到目前为止,用户界面可以正常工作,只是还没有连接起来。只是想分享我到目前为止的发现。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多