【问题标题】:StackViews in StackViews Fill All Equally Based On Smallest ItemStackView 中的堆栈视图均基于最小项填充
【发布时间】:2021-03-07 19:12:04
【问题描述】:

我正在尝试填充未知但计算出的 stackViews 数量,填充未知但计算出数量的 UIImageViews,以相等的间距。

我有一个主要的垂直stackView,它的高度和宽度约束为75。对齐方式:居中;分配:平均填充。

对于每个 subStackView:

        newStack.axis = .horizontal
        newStack.alignment = .center
        newStack.distribution = .fillEqually
        newStack.spacing = 1
        newStack.sizeToFit()
        mainStack.addArrangedSubview(newStack)

然后我有一个不同的循环,它将正确数量的 imageViews 添加到每个 subStackView 中:

            let image = UIImageView()
            image.contentMode = .scaleAspectFit
            image.image = UIImage(systemName: R.Image.System.circle)
            subStackView.addArrangedSubview(image)

下面是结果的屏幕截图。看起来所有 imageView 的大小都相同,但由于某种原因,它们的间距似乎相等,而不是间距为 1。

下面的 3 张图片应该都是五边形,但正如你所见,添加的项目越多,形状就越扭曲。

【问题讨论】:

    标签: swift uikit uistackview


    【解决方案1】:

    这有点棘手......

    我们需要让“点行”(水平堆栈视图)居中,而不是拉伸主堆栈视图的宽度。

    我们还需要实际计算点宽,而不是使用.fillEqually,这样我们就不会得到圆点大小。

    例如:

    • 主栈宽度为 75
    • 1 点间距
    • 3 个水平点

    可用宽度是堆栈视图宽度减去“空格”数 x 间距:

    75 - 2 = 73
    73 / 3 = 24.333333...
    

    @2x 缩放设备上,3 个视图的实际宽度将为:

    24.5 : 24 : 24.5
    

    只有 3 个“点”不是很明显,但是当我们到达 1, 3, 5, 7, 9, 8, 7, 6, 5 模式时会变得非常明显。

    .fillEqually 位于左侧,计算出的整数点大小位于右侧:

    下面是一些示例代码:

    class DotsViewController: UIViewController {
        
        let patterns: [[Int]] = [
            [3, 3, 3],
            [3],
            [1, 2, 3],
            [1, 3, 5, 4, 3],
            [1, 3, 5, 7, 9, 8, 7, 6, 5],
        ]
        
        let mainStack: UIStackView = {
            let v = UIStackView()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.axis = .vertical
            v.alignment = .fill
            v.distribution = .equalSpacing
            return v
        }()
        
        // space between dots
        let dotSpacing: CGFloat = 1
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            view.addSubview(mainStack)
            
            let g = view.safeAreaLayoutGuide
            
            NSLayoutConstraint.activate([
                // constrain main stack view 20-pts from top / leading / bottom
                mainStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
                mainStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
                mainStack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
                
                // width: 75
                mainStack.widthAnchor.constraint(equalToConstant: 75.0),
            ])
            
            patterns.forEach { a in
                // create a vertical stack view
                //  to hold the "rows" of horizontal stack views (containing the dots)
                let vBlockStack = UIStackView()
                vBlockStack.axis = .vertical
                vBlockStack.alignment = .center
                vBlockStack.distribution = .fill
                vBlockStack.spacing = dotSpacing
                // add it to the main stack view
                mainStack.addArrangedSubview(vBlockStack)
    
                // calculate dot size
                //  needs to be a whole number so we don't get
                //  half-point sizes
                let maxDots:CGFloat = CGFloat(a.max()!)
                let availableWidth:CGFloat = 75.0 - ((maxDots - 1) * dotSpacing)
                let w:CGFloat = floor(availableWidth / maxDots)
                
                a.forEach { numDots in
                    // create a horizontal stack view
                    let hDotStack = UIStackView()
                    hDotStack.axis = .horizontal
                    hDotStack.alignment = .fill
                    hDotStack.distribution = .fill
                    hDotStack.spacing = dotSpacing
                    // add it to the vertical block stack view
                    vBlockStack.addArrangedSubview(hDotStack)
                    for _ in 0..<numDots {
                        let v = UIImageView()
                        v.contentMode = .scaleAspectFit
                        v.image = UIImage(systemName: "circle.fill")
                        v.tintColor = .red
                        // add view to dot stack view
                        hDotStack.addArrangedSubview(v)
                        // set dots image view size constraints
                        v.widthAnchor.constraint(equalToConstant: w).isActive = true
                        v.heightAnchor.constraint(equalTo: v.widthAnchor).isActive = true
                    }
                }
                
            }
            
        }
    
    }
    

    产生这个输出:

    【讨论】:

    • 谢谢DonMag。又是你给我的另一个精彩而极其详细的答案。又到了重构的时候了。
    猜你喜欢
    • 2016-05-03
    • 1970-01-01
    • 2016-09-09
    • 2021-05-13
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 2017-07-19
    • 1970-01-01
    相关资源
    最近更新 更多