菜鸟教程小白 发表于 2022-12-12 15:04:42

ios - 如何使约束(自动布局)以编程方式工作


                                            <p><p>这是我的第一个 iOS 项目,因此我在约束和自动布局方面遇到了困难。</p>

<p>这就是我想要做的。我想将 subview 添加到 UIScrollView。这是我以编程方式做的,因为 subview 的数量不是静态的。当我只是添加单个 subview (在代码或 XIB 中)或通过 XIB 添加多个 subview 时,我可以使自动布局和约束完美地工作。但是我无法让它与代码中动态数量的 subview 一起工作。 </p>

<p> subview 的许多实例被创建,但它们都在彼此之上,因为约束不起作用。我希望他们在每个下面排列,这就是为什么我试图让约束起作用。 (现在我只是将 subview 的数量设置为 10,但这只是暂时的)</p>

<p>这是我的一些代码(从按下按钮开始):</p>

<pre><code>-(IBAction) buttonTapped:(id)sender {

UIScrollView *matchScrollView = (UIScrollView *) ;
NSMutableArray *matchViewsArray = [ init];

for (int i = 0; i &lt;= 9; i++) {
    MatchView *newMatchView = [ loadNibNamed:@&#34;MatchView&#34; owner:self options:nil].firstObject;
    ;
}

for (int i = 0; i &lt; ; i++) {
    MatchView *newMatchView = matchViewsArray;

//I kept some IBOutlets out of the code example here. They work fine with a single subview. or even multiple subviews as long as you don&#39;t mind they are all on top of each other due to constraints not working xD
    ;
    ];

   
                                                            attribute:NSLayoutAttributeLeading
                                                            relatedBy:NSLayoutRelationEqual
                                                               toItem:matchScrollView
                                                            attribute:NSLayoutAttributeLeading
                                                             multiplier:1.0
                                                               constant:8.0]];

   
                                                                attribute:NSLayoutAttributeTrailing
                                                                relatedBy:NSLayoutRelationEqual
                                                                   toItem:matchScrollView
                                                                attribute:NSLayoutAttributeTrailing
                                                               multiplier:1.0
                                                               constant:8.0]];

    //If this is not the first object, then the top of the object contraints with the bottom of the previous object
    if (i &gt; 0) {
      // I think the fault may lie here. Do i need to remove the previous constraint, or will it be overwritten? This did not work however, did i remove it wrong?

      //Making sure it only tries to call removeconstraint: once and once only, as the constraint is only put on the else statement which only executes on the very first object. Attempt to fix the code
      if (i == 1) {
      
                                                                  attribute:NSLayoutAttributeTop
                                                                  relatedBy:NSLayoutRelationEqual
                                                                        toItem:matchScrollView
                                                                  attribute:NSLayoutAttributeTop
                                                                  multiplier:1.0
                                                                  constant:8.0]];
      }

       addConstraint:
                                                                  attribute:NSLayoutAttributeTop
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:matchViewsArray
                                                                  attribute:NSLayoutAttributeBottom
                                                                   multiplier:1.0
                                                                     constant:8.0]];
    }

    //The top of the first object constraints with the top of the matchScrollView
    else {
      
                                                                      attribute:NSLayoutAttributeTop
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:matchScrollView
                                                                      attribute:NSLayoutAttributeTop
                                                                     multiplier:1.0
                                                                     constant:8.0]];
    }

    //If this is the last object, then the bottom of the object constraints with the bottom of matchScrollView
    if ( i == - 1) {
      //tried removing the constraint created by else statement first before adding a new constraint
       removeConstraint:
                                                                           attribute:NSLayoutAttributeBottom
                                                                           relatedBy:NSLayoutRelationEqual
                                                                              toItem:matchViewsArray
                                                                           attribute:NSLayoutAttributeTop
                                                                        multiplier:1.0
                                                                            constant:8.0]];

      
                                                                  attribute:NSLayoutAttributeBottom
                                                                  relatedBy:NSLayoutRelationGreaterThanOrEqual
                                                                     toItem:matchScrollView
                                                                  attribute:NSLayoutAttributeBottom
                                                                   multiplier:1.0
                                                                     constant:8.0]];
    }
    //else the bottom of the object contraints with the top of the next object
    else {
       addConstraint:
                                                                  attribute:NSLayoutAttributeBottom
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:matchViewsArray
                                                                  attribute:NSLayoutAttributeTop
                                                                   multiplier:1.0
                                                                     constant:8.0]];
    }

   
                                                                attribute:NSLayoutAttributeCenterX
                                                                relatedBy:NSLayoutRelationEqual
                                                                   toItem:matchScrollView
                                                                attribute:NSLayoutAttributeCenterX
                                                               multiplier:1.0
                                                               constant:0.0]];
}
</code></pre>

<p>}</p>

<p>我不断收到“以 NSException 类型的未捕获异常终止”。我尝试在添加新约束之前删除旧约束,但这没有帮助。除非我删除它们是错误的?</p>

<p>如果我删除所有 if 和 else 语句,只创建一个 subview ,那么约束就可以完美地工作。如果我创建多个 subview ,则应用程序不会崩溃,但 subview 都具有相同的约束并且彼此重叠。因此,通过添加 if 和 else 语句并使用 matchViewsArray 我尝试为多个 subview 设置约束。</p>

<p>此外,即使这段代码有效,真的没有更简单的方法来代替循环中的所有这些 if 和 else 语句吗?</p>

<p>如前所述,这是我的第一个 iOS 项目,因此可能有更有效和更好的方法来实现我想要的行为。</p>

<p>任何帮助将不胜感激。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>很遗憾,我没有制作 iOS 应用程序的许可,也无法按原样对其进行测试,但这个 OSX 代码段可能会有所帮助:</p>

<pre><code>- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
    NSView *contentView = ;

    NSMutableArray *buttons = [ init];

    for (int i = 0; i &lt; 10; i++) {
      NSButton *button = [ initWithFrame:NSZeroRect];
      ;
      ];
      ;
      ]];
      ;

      ;
      ;
    }
    int count = (int);

    // 1. one below other
    // 2. all equal width

    for (int i = 1; i &lt; count; i++) {
      NSView *view1 = buttons;
      NSView *view2 = buttons;
      NSDictionary *views = NSDictionaryOfVariableBindings(view1, view2);

      -&#34;
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];
      &#34;
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];
    }

    // 3. first -&gt; top

    if (count &gt; 0) {
      NSView *view = ;
      NSDictionary *views = NSDictionaryOfVariableBindings(view);

      &#34;
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];
    }

    // 4. last -&gt; bottom

    if (count &gt; 0) {
      NSView *view = ;
      NSDictionary *views = NSDictionaryOfVariableBindings(view);

      -|&#34;
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];
    }

    // 5. left &lt;- all -&gt; right

    for (int i = 0; i &lt; count; i++) {
      NSView *view = buttons;
      NSDictionary *views = NSDictionaryOfVariableBindings(view);

      -(&gt;=20)-|&#34;
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];
    }
}
</code></pre>

<p> <img src="/image/QX4Mr.png" alt="What it looks like"/> </p>

<p>请注意,如果不使用“视觉格式语言”,则无法指定默认的 8/20 间距,因为 <code>constraintsWithVisualFormat:...</code> 会产生特殊的约束(当然,内部带有特殊的私有(private)标志)会自动- 在特定情况下将 8 调整为 6/4/根据 Apple 的 HIG 调整大小。 (您可以尝试在 IB 中放置控件,然后发现默认值并不总是 8,但在运行时突然变为 8!)。</p>

<p><strong>编辑:</strong>此外,您可以始终使用简单的#define 或子例程来隐藏 [[]]梯子。</p>

<p><strong>edit2:</strong>重构阶段:)</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 如何使约束(自动布局)以编程方式工作,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/29661991/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/29661991/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 如何使约束(自动布局)以编程方式工作