无法在自动布局“打开”的情况下移动 UILabel 的 Y 位置

Posted

技术标签:

【中文标题】无法在自动布局“打开”的情况下移动 UILabel 的 Y 位置【英文标题】:Can't move UILabel's Y position with Autolayout "on" in view 【发布时间】:2012-12-24 20:14:22 【问题描述】:

我必须在这里遗漏一些非常明显的东西,但这是一个让我沮丧了好几天的问题。

在 xcode 4.5 上的 ios 项目中,我在一个 XIB 中有几个标签,一个在另一个之上,在一个 UIScrollView 中,它占据了一个 UIView。每个标签都与视图一样宽,每个标签都比下一个高 20 px。有时,其中一个标签没有任何信息,因此它被设置为不可见,并且它下面的标签应该向上移动以占据空白空间。

问题是,如果在视图上选中“关闭”自动布局,标签会完全按照应有的方式向上移动,尽管 UIScrollView 不再滚动。如果是on,则无论如何标签都不会移动。

这是代码...我基本上只是使用一个快速函数将每个标签向上移动不可见标签的高度。

[self moveObjectBy: self.festNameLabel moveByY:-(yearsLabel.frame.size.height-2)];


// this just quickly moves a label. 
- (void)moveObjectBy:(UIView *)lbl moveByY:(int)byHeight 
    CGRect newFrame = lbl.frame;
    NSLog(@"%f, %d", newFrame.origin.y, byHeight);
    newFrame.origin.y += byHeight; //yearsLabel.frame.size.height;
    lbl.frame = newFrame;

当它运行时,NSLog 显示它的 Y 已移动,但它不会在屏幕上移动。我确定它与垂直空间约束有关,但它不会让我删除约束,也不会让我将其更改为视图顶部空间以外的任何内容。就像我说的,我确定我错过了一些东西,但我已经用尽了我所知道的一切......

【问题讨论】:

您设置为隐藏的只是一个特定标签,还是可以是其中任何一个? 它可以是其中任何一个,但如果我能弄清楚如何将它们向上移动,我可以处理它! 我已经编辑了我的答案以允许这样做。 我用一种更简单的方式再次编辑了我的答案。这样,您只需要对每个标签进行垂直约束。 【参考方案1】:

如果您只有一个可能被隐藏的标签,您可以将其下方的标签移至以下位置:

 -(void)contract 
    self.label2.hidden = YES;
    self.con2To1.constant = -34;

顶部标签对滚动视图的顶部有一个约束,所有其他标签对它们上方和下方的标签都有 20 点的垂直距离约束。在这个例子中,我隐藏了 label2。标签都是 34 点高,因此将约束常数从 20 更改为 -34 会将现在隐藏的标签移动到其上方的标签之上。

要将此方法与可以隐藏的多个标签一起使用,您需要为每个要隐藏的标签提供一个出口,并限制其对上面的标签的约束。实际上,您可以在没有约束条件的情况下做到这一点,但我不知道它是否会那么健壮(它可能会选择错误的约束条件)。我可以通过循环遍历约束来找到与特定标签一起使用的约束,并且是该标签顶部的约束:

-(void)hideLabel:(UILabel *) label 
    label.hidden = YES;
    for (NSLayoutConstraint *con in self.scroller.constraints) 
        if (con.firstItem == label  && con.firstAttribute == NSLayoutAttributeTop) 
            con.constant = -34;
        
    

如果您愿意,可以修改相同的方法以使用动画 - 以下 sn-p 淡出您要隐藏的标签,同时为所有较低标签的上移设置动画。

 -(void)hideLabel:(UILabel *) label 
    for (NSLayoutConstraint *con in self.scroller.constraints) 
        if (con.firstItem == label  && con.firstAttribute == NSLayoutAttributeTop) 
            con.constant = -34;
            [UIView animateWithDuration:.5 animations:^
                label.alpha = 0;
                [self.scroller layoutIfNeeded];
            ];
        
    

【讨论】:

我几乎在过去的几天里都在尝试处理约束和框架等,但无济于事,而您编辑的答案基本上在几分钟内就解决了我。我欠你一杯啤酒!【参考方案2】:

使用自动布局,您不能在子视图上设置框架 - 充其量,它会暂时工作,直到发生下一次布局传递。此时,您的约束定义的布局将重新建立。

您需要做的是修改视图上的约束。在您的情况下,在每个标签上设置特定的引脚到高度约束是明智的。然后,您可以为这些约束中的每一个创建出口。对于零高度标签,您需要将相关约束上的常量设置为零。然后下面的标签将向上移动。

根据您要移除的标签,这可能会给您留下两倍宽的间隙。您可以通过修改间距约束来删除它,或者您可以完全摆脱间距约束,只是让每个标签高一点,但彼此相邻 - 标签的内容无论如何都会垂直居中。

主要信息是您没有设置框架。您改为修改、添加和/或删除约束。

【讨论】:

对不起,我比以前更糊涂了!我一直在尝试移动/修改约束,但这很让人抓狂,而且我似乎找不到教程或任何东西让我朝着正确的方向前进!我尝试在标签上设置一个别针到它上面的标签,但是一半的别针是灰色的,或者我只能固定到超级视图。编辑:我在上面添加顶部空间针,上面的视图不可见,没有移动。我迷路了…… 很棒的答案...完全解决了我的问题,让我走上了正轨。非常感谢!【参考方案3】:

如果你想快速完成:

for item in self.view.constraints

    if item.firstItem .isKindOfClass(UITextField)
    
        let newField = item.firstItem as! UITextField
        if newField == answerTextField && item.firstAttribute == NSLayoutAttribute.Top
        
            item.constant = answerFrame.origin.y
            self.view .layoutIfNeeded()
        
    
    if item.firstItem .isKindOfClass(UIButton)
    
        let newField = item.firstItem as! UIButton
        if newField == submitButton && item.firstAttribute == NSLayoutAttribute.Top
        
            item.constant = submitFrame.origin.y
            self.view .layoutIfNeeded()
        
    

【讨论】:

以上是关于无法在自动布局“打开”的情况下移动 UILabel 的 Y 位置的主要内容,如果未能解决你的问题,请参考以下文章

如何在启用自动布局的情况下根据 UILabel 的内容自动更改 UILabel 对象的高度和下方其他元素的位置

Xcode 6 无法在启用自动布局的情况下移动 UIButton

具有自动布局的多行UILabel,如何在不更改标签框架的情况下根据内容调整字体大小?

如何使用自动布局约束为移动 UILabel 设置动画?

如何设置自动布局,以便 UILabel 调整大小并根据需要移动其他视图

首次出现时无法在 UITableViewCell 中更改 UILabel 的框架(使用自动布局)