以编程方式设置约束 [英] Setting constraints programmatically

查看:117
本文介绍了以编程方式设置约束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试如何使用UIScrollView。经过多次麻烦,我终于掌握了它。但是现在我似乎遇到了另一个障碍。

I'm experimenting with how to use UIScrollView. After much trouble, I finally got the hang of it. But now I've seem to hit another snag.

在这个简单的应用程序中,我有一个滚动视图,为了使它工作,我必须设置如此处所述,查看滚动视图约束为0的底部空间,并且工作正常。我是通过IB做的。

In this simple app, I have a scroll view with and in order for it to work, I have to set the view's bottom space to scrollview constraint to 0 as described here and it works fine. I'm doing it through the IB.

现在我遇到了一个必须以编程方式完成该部分的场景。我在 viewDidLoad 方法中添加了以下代码。

Now I've come across a scenario where I have to do that part programmatically. I've added the below code in the viewDidLoad method.

NSLayoutConstraint *bottomSpaceConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                                             attribute:NSLayoutAttributeBottom
                                                                             relatedBy:NSLayoutRelationEqual
                                                                                toItem:self.scrollView
                                                                             attribute:NSLayoutAttributeBottom
                                                                            multiplier:1.0
                                                                              constant:0.0];
[self.view addConstraint:bottomSpaceConstraint];

但它似乎不起作用。它在控制台窗口中输出以下消息,我不知道该怎么做。

But it doesn't seem to work. It outputs the following message in the console window adn i don't know what to make of it.

无法同时满足约束条件。
可能至少以下列表中的一个约束是您不想要的约束。试试这个:(1)看看每个约束并试着找出你不期望的东西; (2)找到添加了不需要的约束或约束的代码并修复它。 (注意:如果你看到你不理解的NSAutoresizingMaskLayoutConstraints,请参阅UIView属性的文档translatesAutoresizingMaskIntoConstraints)



有人可以告诉我怎么做吗?我还附上了一个这里的演示项目,这样你就可以做得更好关于这个问题的想法。

Can someone please tell me how to do this? I've also attached a demo project here so that you can get a better idea on the issue.

更新:

首先感谢您的回复。使用答案中提到的方法,我能够使它工作。然而,它的情况略有不同。现在我正在尝试以编程方式将视图加载到viewcontroller。

First off thanks for the responses. Using the ways mentioned in the answers I was able to get it working. However ina slightly different scenario its not. Now I'm trying to load a view onto a viewcontroller programatically.

如果我可以进一步解释。有2个视图控制器。第一个是 UITableViewController ,第二个是 UIViewController 。在里面一个 UIScrollView 。还有多个 UIView s,其中一些视图的高度超出了屏幕的正常高度。

If I may explain further. There are 2 view controllers. First one being a UITableViewController and the second one a UIViewController. Inside that a UIScrollView. Also There are multiple UIViews and some of those views' height exceeds the normal height of the screen.

UITableViewController 显示选项列表。根据用户的选择,该批次中的特定 UIView 将被加载到 UIViewController 中,并带有 UIScrollView

The UITableViewController displays a list of options. Based on the user's selection, a particular UIView out of the lot will be loaded into the UIViewController with the UIScrollView.

在这种情况下,上述方法不起作用。滚动没有发生。我是否必须做一些不同的事情,因为我单独加载视图?

In this scenario, the above method doesn't work. The scrolling isn't happening. Do I have to do something different since I'm loading the view separately?

我上传了一个演示项目这里,以便您可以看到它的实际效果。请参阅 Email.xib 并从表格视图列表中选择电子邮件

I've uploaded a demo project here so that you can see it in action. Please see the Email.xib and select Email from the table view list.

推荐答案

根据对您的代码的评论,一些评论:

Based upon a review of your code, a few comments:


  1. 您通常不会当视图出现时,需要调整约束。如果您发现自己这样做,通常意味着您没有正确配置故事板(或者至少没有高效配置)。你真正需要设置/创建约束的唯一时间是(a)你是以编程方式添加视图(我建议的是更多的工作而不是它的价值);或者(b)您需要对约束进行一些运行时调整(参见下面第3点下的第三个项目符号)。

  1. You generally don't need to adjust constraints when a view appears. If you find yourself doing this, it often means that you haven't configured your storyboard correctly (or at least, not efficiently). The only time you really need to set/create constraints is either (a) you're adding views programmatically (which I'm suggesting is more work than it's worth); or (b) you need to do some runtime adjustment of constraints (see third bullet under point 3, below).

我不是故意要对它进行处理,但你的项目有一堆冗余代码。例如

I don't mean to belabor it, but your project had a bunch of redundant code. E.g.


  • 您正在设置滚动视图的框架,但这受到约束的约束,因此不执行任何操作(即,应用约束后,将替换任何手动设置的 frame 设置。通常,在自动布局中,不要尝试直接更改 frame :编辑约束。但是,无论如何都不需要改变约束,所以关键是没有实际意义。

  • You were setting the frame for the scroll view, but that is governed by constraints, so that does nothing (i.e. when the constraints are applied, any manually set frame settings will be replaced). In general, in auto layout, don't try changing frame directly: Edit the constraints. But, no changing of constraints is needed at all anyway, so the point is moot.

您正在设置滚动视图的内容大小,但在auto中布局,也受到(子视图)约束的约束,因此这是不必要的。

You were setting the content size for the scroll view, but in auto layout, that, too, is governed by constraints (of the subviews), so that was unnecessary.

您正在设置scrollview的约束(已经为零),但是您没有将NIB中的视图添加到scrollview中,从而击败了任何意图也在那里。最初的问题是如何更改滚动视图的底部约束。但是它的底部约束已经为零,所以我认为没有理由再将其设置为零。

You were setting constraints for the scrollview (which were already zero), but then you weren't adding the view from the NIB into the scrollview, defeating any intent there, too. The original question was how to change the bottom constraint of the scroll view. But the bottom constraint for that is already zero, so I see no reason to set it to zero again.

我建议对你的项目进行更彻底的简化:

I'd suggest a more radical simplification of your project:


  • 你通过存储使自己的生活变得更加困难您对NIB的看法。如果你留在故事板世界里会更容易。如果你真的需要,我们可以帮助你做NIB的事情,但是为什么要让自己的生活变得如此艰难?

  • You're making life much harder on yourself by storing your views in NIBs. It's much easier if you stay within the the storyboard world. We can help you do the NIB stuff if you really need to, but why make life so hard on yourself?

使用细胞原型来促进设计你桌子上的细胞。您还可以定义从单元格到下一个场景的segue。这消除了编写任何 didSelectRowAtIndexPath prepareForSegue 代码的任何需要。显然,如果你有什么需要传递到下一个场景,一定要使用 prepareForSegue ,但到目前为止你所提出的并不需要,所以我评论过在我的示例中。

Use cell prototypes to facilitate the design of the cells in your table. You can also define the segues to go from the cells to the next scene. This eliminates any need to write any didSelectRowAtIndexPath or prepareForSegue code. Clearly, if you have something you need to pass to the next scene, by all means use prepareForSegue, but nothing you've presented thus far requires that, so I've commented it out in my examples.

假设您正在寻找以编程方式更改约束的实际示例,我已设置场景以便文本视图将根据文本视图中的文本以编程方式更改其高度。与往常一样,在改变IB为我创建的现有约束时,不是迭代约束来找到有问题的约束,我认为设置 IBOutlet 对于约束,并直接编辑约束的常量属性,这就是我所做的。所以我将视图控制器设置为文本视图的委托,并编写了一个 textViewDidChange ,它更新了文本视图的高度约束:

Assuming you were looking for a practical example of programmatically changing constraints, I've set up the scene so that the text view will change its height programmatically, based upon the text in the text view. As always, rather than iterating through the constraints to find the one in question, when altering an existing constraint that IB created for me, I think it's far more efficient to set up an IBOutlet for the constraint, and edit the constant property for the constraint directly, so that's what I've done. So I set up the view controller to be the delegate of the text view, and wrote a textViewDidChange that updated the text view's height constraint:

#pragma mark - UITextViewDelegate

- (void)textViewDidChange:(UITextView *)textView
{
    self.textViewHeightConstraint.constant = textView.contentSize.height;
    [self.scrollView layoutIfNeeded];
}

注意,我的文本视图有两个高度限制,一个强制性的最小高度约束,以及我根据文本数量改变的中等优先级约束。重点是它说明了以编程方式更改约束的实际示例。您根本不应该使用scrollview的底部约束,但这显示了您可能想要调整约束的实际示例。

Note, my text view has two height constraints, a mandatory minimum height constraint, and a medium priority constraint that I change above based upon the amount of text. The main point is that it illustrates a practical example of changing constraints programmatically. You shouldn't have to muck around with the scrollview's bottom constraint at all, but this is shows a real-world example of when you might want to adjust a constraint.






在IB中添加滚动视图时,它会自动获取所有约束你需要。您可能不希望以编程方式添加约束(至少在没有删除现有底部约束的情况下)。


When you add a scrollview in IB, it will automatically get all the constraints you need. You probably don't want to be adding a constraint programmatically (at least not without removing the existing bottom constraint).

两种方法可能更简单:


  1. 为现有的底部约束创建 IBOutlet ,例如 scrollViewBottomConstraint 。然后你可以做到

  1. Create an IBOutlet for your existing bottom constraint, say scrollViewBottomConstraint. Then you can just do

self.scrollViewBottomConstraint.constant = 0.0;


  • 或者最初在IB中创建您的视图,其中底部约束为0.0然后您不要必须以编程方式执行任何操作。如果要布置长滚动视图及其子视图,请选择控制器,将其模拟指标从推断设置为自由形式。然后,您可以更改视图的大小,将scrollview的顶部和底部约束设置为零,在滚动视图中布置所需的所有内容,然后在运行时显示视图时,视图将适当调整大小,并且因为您已经将scrollview的顶部和底部约束定义为0.0,它将被正确调整大小。在IB中看起来有点奇怪,但它在应用程序运行时就像魅力一样。

  • Or create your view initially in IB where the bottom constraint is 0.0 and then you don't have to do anything programmatically at all. If you want to layout a long scrollview and it's subviews, select the controller, set it's simulated metrics from "inferred" to "free form". Then you can change the size of the view, set the scrollview's top and bottom constraints to be zero, layout everything you want inside the scroll view, and then when the view is presented at runtime, the view will be resized appropriately, and because you've defined the scrollview's top and bottom constraints to be 0.0, it will be resized properly. It looks a bit odd in IB, but it works like a charm when the app runs.

    如果您决定添加新约束,则可以以编程方式删除旧的底部约束,或者将旧的底部约束的优先级设置为尽可能低,这样您的新约束(具有更高优先级)将优先,并且旧的,低优先级底部约束将优雅地不是应用。

    If you're determined to add a new constraint, you could either programmatically remove the old bottom constraint, or set the old bottom constraints' priority down as low as possible, and that way your new constraint (with higher priority) will take precedence, and the old, low-priority bottom constraint will gracefully not be applied.

    但你绝对不想只添加新的约束。

    But you definitely don't want to just add a new constraint.

    这篇关于以编程方式设置约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆