如何让约束自动调整大小和重新定位横向键盘键

Posted

技术标签:

【中文标题】如何让约束自动调整大小和重新定位横向键盘键【英文标题】:How to have constraints auto resize and reposition keyboard keys for landscape 【发布时间】:2014-07-16 18:39:13 【问题描述】:

我很难弄清楚如何在约束条件下获得我想要的结果。我可以通过编程方式做到这一点,但似乎应该有更好的方法。

基本上我有一个键盘。

    最左边的键(Q)和最右边的键(P)应该离左右两边各3点。

    Q 键和 P 键之间的 8 个键应该在 Q 键和 P 键之间等间距

    键的宽度应伸展以填满 Q 键和 P 键之间的整个空间宽度,同时彼此之间仍保持相等的空间。

基本上,键盘在横向旋转时应该做苹果原生键盘所做的事情。

这可以通过约束来完成,还是我需要在没有约束的情况下以编程方式完成?

【问题讨论】:

嗨@Spentak,我的回答对你有用吗?如果您有具体问题,我可以尝试解决。谢谢。 【参考方案1】:

关于布局

是的。自动布局可以做到这一点。

如果您希望横向和纵向的布局保持相同(我很确定您会这样做),那么一旦设置了约束,一切都应该正常工作。如果你想让他们改变,这是可能的,但我不打算解决这个问题,因为它似乎不需要。

澄清

在你的问题中,你说:

这可以通过约束来完成,还是我需要在没有约束的情况下以编程方式完成?

我不确定,但我想确认您是否了解自动布局不仅仅是界面构建器。您还可以通过操作NSLayoutConstraints 并将它们添加到视图中来非常自然地使用代码中的自动布局。因此,您可能至少有三个选择:

使用自动布局并在 Interface Builder 中设置约束。 使用自动布局并在代码中设置约束。 不要使用自动布局并在 layoutSubviews: 或类似的地方移动视图。

选择 IB 或代码

您可以在 IB 中设置所有这些。每个键都需要两个水平约束和两个垂直约束,因此您将为 26 键键盘管理至少 104 个约束。加位数。和符号。 手动操作会很痛苦,如果你做对了,团队中的某个人(甚至可能是你)会决定键间距只需要再增加一个像素。

键盘网格具有如此多的规律性和如此多的约束,因此只需使用一些代码来设置约束就会容易得多。

明确一点:您仍将使用自动布局,但您将使用代码创建约束,而不是手动维护它们。

在代码中设置约束

我假设您希望键的大小相同。您可以强加这一点,以及它们之间的相等(指定)间距以及在超级视图左右两侧的固定边距,并具有如下约束:

// Substitute your view names here.
UIButton *q, *w, *e, *r, *t, *y, *u, *i, *o, *p;

NSDictionary *const metrics = @@"margin": @(3), @"gap": @(4);
NSDictionary *const views = NSDictionaryOfVariableBindings(q,w,e,r,t,y,u,i,o,p);
NSArray *const constraints =
  [NSLayoutConstraint
   constraintsWithVisualFormat:
   @"H:|-margin-[q]-gap-[w(q)]-gap-[e(q)]-gap-[r(q)]-gap-[t(q)]-gap-[y(q)]-gap-[u(q)]-gap-[i(q)]-gap-[o(q)]-gap-[p(q)]-margin-|"
   options: NSLayoutFormatDirectionLeadingToTrailing
   metrics: metrics
   views: views];

// Add constraints to your container view so that they do something.
UIView *const container = [self view];
[container addConstraints: constraints];

但我很想构建一个辅助方法,该方法将采用一组视图并从中生成约束。它会是这样的:

-(NSArray *) constraintsForEqualSizeViews: (NSArray *) keys
                      withSuperviewMargin: (CGFloat) margin
                                 andSpace: (CGFloat) space

  NSMutableArray *const constraints = [NSMutableArray new];
  
  // Note: the keys must be in a superview by now so that
  // a constraint can be set against its edge.
  UIView *const leftKey = [keys firstObject];
  [constraints addObject:
   [NSLayoutConstraint constraintWithItem: leftKey
                                attribute: NSLayoutAttributeLeft
                                relatedBy: NSLayoutRelationEqual
                                   toItem: [leftKey superview]
                                attribute: NSLayoutAttributeLeft
                               multiplier: 0
                                 constant: margin]];
  
  UIView *const rightKey = [keys firstObject];
  [constraints addObject:
   [NSLayoutConstraint constraintWithItem: rightKey
                                attribute: NSLayoutAttributeRight
                                relatedBy: NSLayoutRelationEqual
                                   toItem: [rightKey superview]
                                attribute: NSLayoutAttributeRight
                               multiplier: 0
                                 constant: margin]];
  
  UIView *const templateKeyForEqualSizes = leftKey;
  NSDictionary *const metrics = @@"space": @(space);
  for(NSUInteger i=1; i<[keys count]; ++i)
  
    NSDictionary *const views = @@"previousKey": keys[i-1],
                                  @"thisKey": keys[i],
                                  @"templateKey": templateKeyForEqualSizes;

    [constraints addObjectsFromArray:
     [NSLayoutConstraint constraintsWithVisualFormat: @"H:[previousKey]-space-[thisKey(templateKey)]"
                                             options: NSLayoutFormatDirectionLeftToRight
                                             metrics: metrics
                                               views: views]];
  
  
  NSArray *const immutableArrayToReturn = [constraints copy];
  return immutableArrayToReturn;

Apple's documentation 中描述了自动布局语言。

UIView 框架

您无需考虑为键视图设置原始框架 - 这是远离界面构建器来描述键的另一个原因。您可以像这样创建视图:

-(NSArray*) keyRowArray: (NSString*) keyNamesString

  const NSUInteger keyCount = [keyNamesString length];
  NSMutableArray *const keys = [NSMutableArray arrayWithCapacity: keyCount];
  
  for(NSUInteger i=0; i<keyCount; ++i)
  
    NSString *const keyName = [keyNamesString substringWithRange:NSMakeRange(i, 1)];

    // Look! No frame needed!
    XXYourCustomKeyView *const key = [XXYourCustomKeyView new];

    // Do key setup – you probably want to add button actions, and such.
    [key setName: keyName];
    [keys addObject: keyName];
  
  
  return [keys copy];

UIView所有权

我不会直接在 UIViewController 中管理所有这些键。我会将它们封装在一个XXYourCustomKeyboardView 类中,该类可以接受键盘描述(类似于键盘行的字符串数组)。您的控制器可以创建它,传递配置,将自己设置为委托和快乐的日子。

混合 I.B. + 代码方法

您也可以使用混合方法,在 IB 中设置一些键和约束:

非字符键:tab、shift 等。它们的自定义大小和特殊行为。 每一行的左右键。 从方形网格偏移行的交替。

然后您可以使用与上述类似的代码在它们之间添加键。

使用我上面给出的约束创建方法,如果将其拆分为NSLayoutConstraint 上的一个类别中的单独方法,您可能会发现它更灵活:

@interface NSLayoutConstraint (Keyboard)
  // This is what it constraint method currently creates in the for loop.
  +(NSArray*) constraintsForViews: (NSArray*) views imposingEqualSpace: (CGFloat) space;
  +(NSArray*) constraintsForViewsImposingEqualWidth: (NSArray*) views;
  
  // This will also be useful to align a whole row.
  +(NSArray*) constraintsForViewsImposingSameTopAndBottom: (NSArray*) views;
@end

如果有任何不清楚的地方,请在 cmets 中告诉我。如有必要,我会添加说明。

【讨论】:

以上是关于如何让约束自动调整大小和重新定位横向键盘键的主要内容,如果未能解决你的问题,请参考以下文章

UIView 使用约束自动布局居中和调整大小

启动屏幕未调整横向大小

如何允许自动调整UIButton的大小以满足间距约束

如何防止在横向上自动调整 UINavigationBar 的大小

UITableViewController 未根据输入调整大小

让 UITableViewCell 使用自动布局调整自身大小