如何在视图之间创建具有可变间距的UIStackView?

yur*_*ura 62 ios-autolayout ios9 uistackview

我有一个简单的横向 UIStackView,里面堆叠了几个UIViews.我的目标是在视图之间创建可变间距.我很清楚我可以使用"spacing"属性在子视图之间创建恒定的空间.但是我的目标是创建可变空间.请注意,如果可能的话,我希望避免使用充当间隔物的隐形视图.

我想出的最好的方法是将我UIViews的内容包装起来UIStackView,并layoutMarginsRelativeArrangement = YES用来尊重内部堆栈的布局边距.我希望我可以做任何类似的事情UIView而不诉诸于这种丑陋的工作.这是我的示例代码:

// Create stack view
UIStackView *stackView = [[UIStackView alloc] init];
stackView.translatesAutoresizingMaskIntoConstraints = NO;
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.alignment = UIStackViewAlignmentCenter;
stackView.layoutMarginsRelativeArrangement = YES;

// Create subview
UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
// ... Add Auto Layout constraints for height / width
// ...
// I was hoping the layoutMargins would be respected, but they are not
view1.layoutMargins = UIEdgeInsetsMake(0, 25, 0, 0);

// ... Create more subviews
// UIView view2 = [[UIView alloc] init];
// ...

// Stack the subviews
[stackView addArrangedSubview:view1];
[stackView addArrangedSubview:view2];
Run Code Online (Sandbox Code Playgroud)

结果是一个堆栈,其视图彼此相邻,间距为:

在此输入图像描述

Rob*_*ack 99

更新适用于iOS 11,具有自定义间距的StackView

Apple已添加在iOS 11中设置自定义间距的功能.您只需在每个排列的子视图后指定间距.不幸的是,您之前无法指定间距.

stackView.setCustomSpacing(10.0, after: firstLabel)
stackView.setCustomSpacing(10.0, after: secondLabel)
Run Code Online (Sandbox Code Playgroud)

仍然比使用自己的观点更好.

适用于iOS 10及以下版本

您可以简单地将透明视图添加到堆栈视图中,并为它们添加宽度约束.

(标签 - UIView - 标签 - UIView -Label)

如果你继续distribution填充,那么你可以在你的UIViews上设置可变宽度约束.

但是如果是这种情况,我会考虑使用stackviews是否正确.Autolayout使得在视图之间设置可变宽度变得非常容易.

  • 谢谢,但我希望我不必诉诸空白视图来增加空间或回到自动布局.虽然如果UIStackView不支持我的用例,我可能还需要. (2认同)
  • 为什么要间距变化?如果使用"分布"'相等居中',则可以有可变间距.这将使中心的宽度相等,但间距会有所不同.更多地了解您的用例. (2认同)
  • 基本上,我有几个视图需要水平(或垂直)分布,视图之间具有预定的空间,这些空间可能具有相同的值,也可能不同。我希望能够使用 layoutMargins 或其他一些机制来指定这些边距。 (2认同)

Ugo*_*lli 5

快速 4

遵循lilpit回答,这是UIStackView的扩展,用于向您的排列子视图添加顶部和底部间距

extension UIStackView {
    func addCustomSpacing(top: CGFloat, bottom: CGFloat) {

        //If the stack view has just one arrangedView, we add a dummy one
        if self.arrangedSubviews.count == 1 {
            self.insertArrangedSubview(UIView(frame: .zero), at: 0)
        }

        //Getting the second last arrangedSubview and the current one
        let lastTwoArrangedSubviews = Array(self.arrangedSubviews.suffix(2))
        let arrSpacing: [CGFloat] = [top, bottom]

        //Looping through the two last arrangedSubview to add spacing in each of them
        for (index, anArrangedSubview) in lastTwoArrangedSubviews.enumerated() {

            //After iOS 11, the stackview has a native method
            if #available(iOS 11.0, *) {
                self.setCustomSpacing(arrSpacing[index], after: anArrangedSubview)
                //Before iOS 11 : Adding dummy separator UIViews
            } else {
                guard let arrangedSubviewIndex = arrangedSubviews.firstIndex(of: anArrangedSubview) else {
                    return
                }

                let separatorView = UIView(frame: .zero)
                separatorView.translatesAutoresizingMaskIntoConstraints = false

                //calculate spacing to keep a coherent spacing with the ios11 version
                let isBetweenExisitingViews = arrangedSubviewIndex != arrangedSubviews.count - 1
                let existingSpacing = isBetweenExisitingViews ? 2 * spacing : spacing
                let separatorSize = arrSpacing[index] - existingSpacing

                guard separatorSize > 0 else {
                    return
                }

                switch axis {
                case .horizontal:
                    separatorView.widthAnchor.constraint(equalToConstant: separatorSize).isActive = true
                case .vertical:
                    separatorView.heightAnchor.constraint(equalToConstant: separatorSize).isActive = true
                }

                insertArrangedSubview(separatorView, at: arrangedSubviewIndex + 1)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你会像这样使用它:

//Creating label to add to the UIStackview
let label = UILabel(frame: .zero)

//Adding label to the UIStackview
stackView.addArrangedSubview(label)

//Create margin on top and bottom of the UILabel
stackView.addCustomSpacing(top: 40, bottom: 100)
Run Code Online (Sandbox Code Playgroud)