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

Spe*_*tak 3 objective-c ios autolayout nslayoutconstraint ios8

我很难弄清楚如何通过约束来获得我想要的结果.我可以通过编程方式执行此操作,但似乎应该有更好的方法.

基本上我有一个键盘.

  1. 最左边的键(Q)和最右边的键(P)应该是从左侧和右侧的3个点.

  2. Q键和P键之间的8个键应在Q和P键之间等间隔

  3. 键应该在宽度上拉伸以填充Q和P键之间的整个空间宽度,同时仍然保持彼此之间的相等空间.

基本上键盘应该像Apple的原生键盘在横向旋转时那样做.

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

Ben*_*ohn 9

在布局上

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

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

澄清

在你的问题中,你说:

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

我不确定,但我想检查一下,你知道Auto Layout不仅仅是一个界面构建器.您也可以通过操作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];
Run Code Online (Sandbox Code Playgroud)

但是我很想构建一个辅助方法,它可以获取一系列视图并从中生成约束.它会是这样的:

-(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;
}
Run Code Online (Sandbox Code Playgroud)

Apple的文档中描述了自动布局语言.

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];
}
Run Code Online (Sandbox Code Playgroud)

UIView 所有权

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

混合IB +代码方法

您也可以使用混合方法在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
Run Code Online (Sandbox Code Playgroud)

如果有任何不清楚的地方,请在评论中告诉我.如有必要,我会加上澄清.