如何使用内部 XIB 为动态 UIStackView 设置对齐方式

How to set alignments right for dynamic UIStackView with inner XIB

我原来的ViewController只有一个这样的scrollView:

现在我也有了自己的xib文件(CheckBoxView),主要由一个按钮组成,看这个截图:

我动态创建了一些 UIStackView 并将它们添加到 ScrollView 在这些 UIStackView 中我添加了我的 xib 文件的多个实例。

我想要实现的是,StackViews 只是垂直堆叠。在 StackViews 中,我的 xib-file 中的 UIViews 也应该垂直堆叠。

目前看起来是这样的:

所以 xib-Views 不在整个视图中。由于我使用的是 multi-os-engine,因此我无法提供 swift/obj-c 代码。但这是我的 Java-Code:

for (ItemConfiguration config : itemInstance.getConfigurations()) {

            List<DLRadioButton> radioButtons = new ArrayList<DLRadioButton>();

            UIStackView configView = UIStackView.alloc().initWithFrame(new CGRect(new CGPoint(0, barHeight), new CGSize(displayWidth, displayHeight - barHeight)));
            configView.setAxis(UILayoutConstraintAxis.Vertical);
            configView.setDistribution(UIStackViewDistribution.EqualSpacing);
            configView.setAlignment(UIStackViewAlignment.Center);
            configView.setSpacing(30);


            for (ConfigurationOption option : config.getOptions()) {
                UIView checkBox = instantiateFromNib("CheckBoxView");
                for (UIView v : checkBox.subviews()) {
                    if (v instanceof DLRadioButton) {
                        ((DLRadioButton) v).setTitleForState(option.getName(), UIControlState.Normal);
                        //((DLRadioButton) v).setIconSquare(true);
                        radioButtons.add((DLRadioButton) v);
                    }
                }
                configView.addArrangedSubview(checkBox);
            }
            // group radiobuttons
            //groupRadioButtons(radioButtons);

            configView.setTranslatesAutoresizingMaskIntoConstraints(false);
            scrollView().addSubview(configView);

            configView.centerXAnchor().constraintEqualToAnchor(scrollView().centerXAnchor()).setActive(true);
            configView.centerYAnchor().constraintEqualToAnchor(scrollView().centerYAnchor()).setActive(true);
        }


private UIView instantiateFromNib(String name) {
    return (UIView) UINib.nibWithNibNameBundle(name, null).instantiateWithOwnerOptions(null, null).firstObject();
}

我需要如何设置 Alignments 等来实现我想要的。它应该是这样的:

我不知道是否有理由不使用 UITableView,我强烈建议您使用它。如果不可能,您可以在下面找到一些应该有所帮助的建议。


如果您使用自动布局,您应该为代码中实例化的所有视图设置约束。约束必须全面,iOS 才能了解每个视图的位置和大小。

删除冗余约束

configView.centerXAnchor().constraintEqualToAnchor(scrollView().centerXAnchor()).setActive(true);
configView.centerYAnchor().constraintEqualToAnchor(scrollView().centerYAnchor()).setActive(true);

这两个限制对我来说没有意义。您需要将堆栈视图堆叠在您的 ScrollView 中,但不居中。如果我正确理解你的目标,这应该被删除

为 UIStackViews

设置 width/x-position 约束
configView.setTranslatesAutoresizingMaskIntoConstraints(false);
scrollView().addSubview(configView);

在将堆栈视图添加到 ScrollView 之后,您需要立即为其设置约束。我将在 swift 中提供我的代码,但它看起来与您的 Java 代码所做的非常相似,因此希望您能够毫无困难地转换它:

NSLayoutConstraint.activate([
  configView.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor),
  configView.trailingAnchor.constraintEqualToAnchor(scrollView.trailingAnchor)
]);

为 UIStackViews 设置高度限制

无论何时您在其中添加排列视图,StackViews 都不会更改其大小。因此,您需要自己计算所需的堆栈视图大小,并通过约束明确指定。它应该足以容纳项目和它们之间的空间。我想所有的项目应该是相同的大小,假设是 32 点,那么高度应该是:

let stackViewHeight = items.count * 32 + stackView.space * (items.count + 1)

并为堆栈视图创建新的高度约束:

configView.heightAnchor.constraint(equalToConstant: stackViewHeight).isActive = true

设置 UIStackView 的 y 位置

这是一个更具挑战性的部分,但对于视图在滚动视图中正常工作最重要。

1) 改变循环以了解 UIStackView 的索引

滚动视图应该始终知道其内容的高度,因此您需要了解哪个堆栈视图在顶部,哪个在底部。为此,您需要将每个循环更改为 for(;;) loop:

for (int i = 0; i < itemInstance.getConfigurations().length; i++) {
  ItemConfiguration config = itemInstance.getConfigurations()[i]
  ...
}

我不知道你的数组是什么类型的,所以如果没有下标功能,就用相应的方法替换它。

2) 为堆栈视图设置顶部锚点

对于数组中的第一个堆栈视图,顶部锚点应等于滚动视图顶部锚点,对于其他视图,它应该是前一个堆栈视图的底部锚点 + 它们之间的间距(例如,本例中为 8 点):

if i == 0 {
  configView.topAnchor.constraintEqualToAnchor(scrollView.topAnchor, constant: 8).isActive = true
} else {
  let previousConfigView = itemInstance.getConfigurations()[i - 1]
  configView.topAnchor.constraintEqualToAnchor(previousConfigView.bottomAnchor, constant: 8).isActive = true
}

3) 为最后一个堆栈视图设置底部锚点

如前所述 - 要让滚动视图知道内容大小,我们需要指定相应的约束:

if i == itemInstance.getConfigurations() - 1 {
  configView.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor, constant: 8).isActive = true
}

注意:请注意,所有约束都应设置在已添加到滚动视图的视图上。