iOS:使用 NSLayoutConstraint 将对象堆叠在一起
Posted
技术标签:
【中文标题】iOS:使用 NSLayoutConstraint 将对象堆叠在一起【英文标题】:iOS: Stack objects on top of each other using NSLayoutConstraint 【发布时间】:2013-12-20 18:16:31 【问题描述】:我想将几个按钮堆叠在一起,然后显示/隐藏它们作为一种切换方式。 (想想视频播放器中的播放/暂停/重播按钮)。
是否可以使用 NSLayoutConstraint 来做到这一点?
或者,也许有更好的方法在 ios 中创建多状态按钮?
这是我尝试过的,但显然不起作用,因为它将它们放在一起:
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat:@"|[_playButton][_pauseButton][_replayButton][_scrubber][_minimizeButton]|"
options:0
metrics:nil
views:viewsDictionary];
使用下面@dasdom 的一些技巧,我想出了以下几点:
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat:@"|[_pauseButton]-[_scrubber]-[_minimizeButton]|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:viewsDictionary];
[constraints arrayByAddingObjectsFromArray:[NSLayoutConstraint
constraintsWithVisualFormat:@"|[_playButton]"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:viewsDictionary]];
[constraints arrayByAddingObjectsFromArray:[NSLayoutConstraint
constraintsWithVisualFormat:@"|[_replayButton]"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:viewsDictionary]];
[self addConstraints:constraints];
非常接近 - 水平间距是正确的,并且对于第一条规则中的项目(pauseButton、scrubber、minimize)它们垂直对齐正确,但是播放和重播按钮太高了......好像随后的NSLayoutFormatAlignAllCenterY
将被忽略。
Edit2:这是我最终得到的代码,比我想象的要多得多,但似乎运行良好:
NSDictionary *metrics = @
@"buttonPadding": @(kBarPaddingX)
;
// Align along Y center and set order, so scrubber stretches in the middle.
NSString *controlsVisualFormat =
@"|-buttonPadding-[_playButton]-[_scrubber]-[_minimizeButton]-buttonPadding-|";
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat:controlsVisualFormat
options:NSLayoutFormatAlignAllCenterY
metrics:metrics
views:viewsDictionary];
// Set alignment of pauseButton and replayButton
constraints = [constraints arrayByAddingObjectsFromArray:[NSLayoutConstraint
constraintsWithVisualFormat:@"|-buttonPadding-[_pauseButton]"
options:NSLayoutFormatAlignAllCenterY
metrics:metrics
views:viewsDictionary]];
constraints = [constraints arrayByAddingObjectsFromArray:[NSLayoutConstraint
constraintsWithVisualFormat:@"|-buttonPadding-[_replayButton]"
options:NSLayoutFormatAlignAllCenterY
metrics:metrics
views:viewsDictionary]];
// Not sure why using NSLayoutFormatAlignAllCenterY above doesn't center the buttons vertically,
// so we need another set of constraints to center them vertically.
constraints = [constraints arrayByAddingObject:
[NSLayoutConstraint constraintWithItem:_pauseButton
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:_pauseButton.superview
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0]];
constraints = [constraints arrayByAddingObject:
[NSLayoutConstraint constraintWithItem:_replayButton
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:_replayButton.superview
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0]];
【问题讨论】:
我知道您已经接受了答案,但您确定您的布局没有歧义吗?在 viewDidAppear: 中设置断点,然后在调试器中剪切并粘贴以下内容: po [[UIWindow keyWindow] _autolayoutTrace]. 是的,有什么解决办法吗? 您的contraintsWithVisualFormat
前面是否需要包含H:
和V:
?
【参考方案1】:
你可以试试
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat:@"|[_playButton(==_pauseButton)]"
options:0
metrics:nil
views:viewsDictionary];
constraints = [NSLayoutConstraint
constraintsWithVisualFormat:@"V:|[_playButton(==_pauseButton)]"
options:0
metrics:nil
views:viewsDictionary];
[self addConstraint:[NSLayoutConstraint constraintWithItem:_playButton
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:_pauseButton
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:_playButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_pauseButton
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f]];
【讨论】:
你的意思是用_playButton
代替_infoButton
吗?
这段代码给了我一些尝试的想法,所以我更新了我的代码(见更新的 q)。我现在只需要弄清楚播放/重播按钮的垂直间距。知道为什么NSLayoutFormatAlignAllCenterY
不适用于这些吗?由于某种原因,它们高于其他元素。
给了你答案,虽然它需要更多的代码(见我的第二次编辑!)干杯!【参考方案2】:
这个答案解决了Edit2下的代码。
你很好地构建了一个漂亮的水平行各种按钮,即_playButton
-> _minimizeButton
。但是,格式选项NSLayoutFormatAlignAllCenterY
仅将每个按钮相对于所有其他按钮垂直对齐。您还没有建立一个规则来沿垂直轴定位按钮行相对于行的容器视图。
由于所有按钮已经相互垂直对齐,因此您只需为其中一个按钮(任何按钮)添加垂直轴类型约束。这是一个假设的示例,它将播放按钮的顶部固定在容器视图顶部的 40 点上。如果你想要一个更实际的例子,我需要对整体布局有更好的了解。
[[containerView addConstraint:[NSLayoutConstraint constraintWithItem:_playButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeTop multiplier:1.0f constant:40.0f]];
【讨论】:
以上是关于iOS:使用 NSLayoutConstraint 将对象堆叠在一起的主要内容,如果未能解决你的问题,请参考以下文章
IOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry) 转载
iOS7中的NSLayoutConstraint动画持续时间