【问题标题】:How to add a UITextField to UIToolbar with flexible width in iOS 11 using auto-layout如何在 iOS 11 中使用自动布局将 UITextField 添加到具有灵活宽度的 UIToolbar
【发布时间】:2018-03-13 01:20:25
【问题描述】:

我想将 UITextField 添加到 UITooolbar 并让 UITextField 根据需要扩展其宽度以填充该区域,就像 UIBarButtonSystemItemFlexibleSpace 一样。

下面是关于我通常如何在视图控制器中设置工具栏项的 sn-p ...

// two UIBarButtonItems
UIBarButtonItem *left = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:nil];
UIBarButtonItem *right = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:nil action:nil];

// the UIBarButtonItem with a UITextField as custom view
UITextField *textField = [[UITextField alloc] init];
textField.borderStyle = UITextBorderStyleRoundedRect;
UIBarButtonItem *text = [[UIBarButtonItem alloc] initWithCustomView:textField];

[self setToolbarItems:@[left, text, right]];

...然后会像这样显示。

在 iOS 11 之前,我对 UIToolbar 进行了子类化,并使用 layoutSubviews 方法获取所有“非灵活”项目的宽度 (CGRectGetWidth(itemView.frame)),并计算文本字段视图框架的可用宽度。 在 iOS 11 中,Apple 更改为自动布局所有条形,如 WWDC2017 session 204 所述,现在 CGRectGetWidth(itemView.frame) 方式在视图可见之前不会提供有效宽度,iOS 11 UIBarButtonItem images not sizing 也指出了这一点。

我现在如何使用约束和自动布局添加具有自定义视图的灵活大小的 UIBarButtonItems,这将扩展以填充两个项目之间的完整空闲区域?

编辑 1:

如果我只添加文本字段,项目将按预期扩展其宽度。

编辑 2:

在 UIToolbar 中直接使用约束似乎是不可能的,因为项目视图不存在(直到它们被放置?)或者没有超级视图。

UIBarButtonItem *left = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:nil];
UIView *leftView = [left valueForKey:@"view"];
UIBarButtonItem *right = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:nil action:nil];
UIView *rightView = [right valueForKey:@"view"];

UITextField *textField = [[UITextField alloc] init];
textField.borderStyle = UITextBorderStyleRoundedRect;
UIBarButtonItem *text = [[UIBarButtonItem alloc] initWithCustomView:textField];

NSDictionary *views = NSDictionaryOfVariableBindings(leftView, textField, rightView);
NSString *formatString = @"|-[leftView]-[textField]-[rightView]-|";

NSArray *constraint = [NSLayoutConstraint constraintsWithVisualFormat:formatString options:NSLayoutFormatAlignAllCenterX metrics:nil views:views];
[NSLayoutConstraint activateConstraints:constraint];

[self setToolbarItems:@[left, text, right]];

编辑 3:

有了检查view hierarchy for UIToolbar 的想法,我最终得到了以下代码来添加约束...

// _UIToolbarContentView
//   + _UIButtonBarStackView
//       + _UIButtonBarButton
//       + UIView
//       + _UITAMICAdaptorView
//       + UIView
//

UIView *contentView = nil;
for (UIView *view in self.navigationController.toolbar.subviews) {
    if ([view.description containsString:@"ContentView"]) {
        contentView = view;
    }
}

UIView *stackView = nil;
for (UIView *view in contentView.subviews) {
    if ([view.description containsString:@"ButtonBarStackView"]) {
        stackView = view;
    }
}

// constrain views on stack
UIView *uiButtonBarButton = [stackView.subviews objectAtIndex:0];
[uiButtonBarButton.leadingAnchor constraintEqualToAnchor:stackView.leadingAnchor].active = YES;

UIView *uiTAMICAdaptorView = [stackView.subviews objectAtIndex:2];
[uiTAMICAdaptorView.leadingAnchor constraintEqualToAnchor:uiButtonBarButton.trailingAnchor].active = YES;
[uiTAMICAdaptorView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;

... 这将像这样改变视图:

为什么 UIBarButton 被调整大小而不是 UITextField aka UITAMICAdaptorView?

使用约束修复 UIBarButton 的大小 ...

[uiButtonBarButton.widthAnchor constraintEqualToConstant:CGRectGetWidth(uiButtonBarButton.frame)].active = YES;

...看起来像...

...可惜UIButtonBarButton的frame在item被放置之前是无效的。

那么如何在不知道的情况下限制 UIButtonBarButton 的宽度。像“notGreaterThanNecessary”这样的东西?

【问题讨论】:

  • 我有一个类似的问题并写了一些东西作为解决方案。看看:stackoverflow.com/questions/46581263
  • @lucasl 这不是我要找的,但遍历工具栏子视图的想法很棒。我用新知识编辑了我的问题。
  • 从 iOS 11 开始,添加到 UIToolBar 的 UIBarButtonItems 不再具有 superView,因此我们无法在加载视图时设置它们的约束
  • @mnabaa 据我所知,在 iOS 11 之前,这些项目没有 superView,但它们仍然是视图,我们可以设置它们的大小。从 iOS 11 开始,这些项目视图的大小和放置通过使用仅在视图上才有可能的自动布局进行。正如问题中所指出的,每个项目都是放置在 stackView 中的视图。但直到现在我还没有找到一种方法来改变这些“系统约束”的边距、宽度和高度。
  • @grethi 你解决了这个问题吗?如果是,你是怎么做到的?

标签: objective-c uitextfield nslayoutconstraint uitoolbar ios11


【解决方案1】:

将单个 UIView 直接放入单个 UIBarButtonItem,这将成为 UIToolBar 的全宽。

现在你可以像往常一样使用布局约束添加任何你想要的子视图。水平的 UIStackView 在这里可以很好地工作。

【讨论】:

    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 1970-01-01
    • 2015-08-31
    • 2013-02-05
    相关资源
    最近更新 更多