【问题标题】:How to make horizontal UIStackView wrap height content with UIImageView as its children?如何以 UIImageView 作为其子项使水平 UIStackView 包装高度内容?
【发布时间】:2021-06-11 08:47:30
【问题描述】:

我有以下横UIStackView

  1. 黄色背景
  2. 前导、顶部和尾部与安全区域相同
  3. 对齐 = 顶部
  4. 分配 = 按比例填充

UILabel 作为孩子

如果我将UILabel 添加为其子级,它将自动将高度内容包装如下


UIImage 作为孩子

我用 3 个相同的 UIImageView 替换 UILabel

每个UIImageView 都有以下属性

  1. 内容模式 = Aspect Fit

如下图

我想知道,我怎样才能让水平的UIStackView 换行到它的高度内容?

我希望UIStackView 将包裹UIImageView 的内容高度。因此,我们不会观察到UIStackView 的任何黄色背景。

请问,我怎样才能做到这一点?

到目前为止,我已经尝试过使用

  1. UIStackView 和 UIImageView 的内容拥抱优先级
  2. UIStackView 和 UIImageView 的内容压缩阻力优先级

仍然无法达到我想要的结果。


以下是原图源,为606x404

【问题讨论】:

  • 运行时模拟器的行为与xcode的视图编辑器相同。
  • @CheokYanCheng - 每一个图片都会是606 x 404吗?或者你想要 3 个等宽的“部分”,每个 imageView 都设置为Aspect Fit?或者,您想要 3 个可变宽度“部分”,每个图像的高度相同,但宽度不同?
  • 我的最终目标是实现以下目标 - i.imgur.com/98JjT6U.png 在 Android 中,执行权重计算后,我可以告诉 LinearLayout(又名 StackView)我想要第一张图像的 10% 宽度,50% 宽度第二张图片和第三张图片的 40% 宽度。图像高度将根据重量和纵横比进行调整。然后,LinearLayout 将自动包裹其高度以包裹调整后的图像高度。现在,我尝试从最简单的情况开始(所有 3 张相同的图像),但卡住了。
  • @SandeepBhandari 没有。这绝对可以实现。如上面简单的例子,对于一个宽度为 428 的屏幕,我们需要将每个图像缩放到 142.667 x 95.111。然后,它可以完全填充宽度并尊重原始图像的纵横比。
  • 从您发布的演示屏幕截图和解释中,我无法清楚地看到您建议的方式是如何工作的。我的预期结果如下 - i.imgur.com/t9CxDIk.png 您发布的所有屏幕截图仅包含 1 只小猫而不是 3 只小猫。

标签: ios swift


【解决方案1】:

您无法仅通过 Storyboard 设置获得此结果 - 您需要一些代码。

根据显示所需输出的图像,您希望每个“行”:

  • 有 3 张图片
  • 以原始纵横比显示它们
  • 图像之间的小间距(例如 4 点)
  • 适合,使宽度和高度保持比例

第一条评论 - 忘记堆栈视图上的Distribution = Fill Proportionally

对于这个布局,堆栈视图应该是:

  • Axis: Horizontal
  • Alignment: Fill
  • Distribution: Fill
  • Spacing: 4

所以,我们需要做的是根据图像的纵横比(高度/宽度)来约束每个 imageView 的纵横比。

这是一个完整的例子……它使用了这 6 张图片:

我们还将使用相同的设置(除了Axis: Vertical)将水平堆栈视图嵌入到垂直堆栈视图中。

class AdjustStackViewController: UIViewController {
    
    var vStack = UIStackView()
    
    var picNames: [String] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // six images, named "p1" - "p6"
        for i in 1...6 {
            picNames.append("p\(i)")
        }
        
        // vertical stack view
        vStack.axis = .vertical
        vStack.spacing = 4
        
        // use auto-layout
        vStack.translatesAutoresizingMaskIntoConstraints = false
        
        // add it to the view
        view.addSubview(vStack)
        
        // respect safe-area
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            // constrain vStack
            //  Top + 20
            //  Leading and Trailing 0
            vStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            vStack.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            vStack.trailingAnchor.constraint(equalTo: g.trailingAnchor),
        ])
        
        fillStacks()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // re-fill images in new (shuffled) order
        fillStacks()
    }
    
    func fillStacks() -> Void {
        
        // remove existing horizontal stack views (if needed)
        vStack.arrangedSubviews.forEach { v in
            v.removeFromSuperview()
        }
        
        let shuffledImages = picNames.shuffled()

        // two horizontal stack views each with 3 images
        var picNum: Int = 0
        for _ in 1...2 {
            let hStack = UIStackView()
            hStack.spacing = 4
            vStack.addArrangedSubview(hStack)
            for _ in 1...3 {
                // make sure we can load the images
                guard let img = UIImage(named: shuffledImages[picNum]) else {
                    fatalError("Could not load images!")
                }
                // create Image View
                let imgView = UIImageView()
                // set the image
                imgView.image = img
                // proportional constraint based on image dimensions
                imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor, multiplier: img.size.height / img.size.width).isActive = true
                // add to hStack
                hStack.addArrangedSubview(imgView)
                // increment pic number
                picNum += 1
            }
        }

    }
    
}

它的外观如下:

当你运行它时,每次你点击视图时,它都会打乱图像的顺序,这样你就可以看到布局是如何适应的。

【讨论】:

  • 为 ImageView 提供相对约束是一种非常好的技术。我一直认为在使用“Distribution = Fill”时,我需要使用拥抱/压缩。处理“分布=按比例填充”,我需要覆盖子视图intrinsicContentSize。现在我学到了一些新东西。谢谢。
  • @CheokYanCheng - 正如我所提到的,在堆栈视图中忘记Distribution = Fill Proportionally。它很少按照您的预期进行,如果堆栈视图的 Spacing 不等于零,它真的会变得很不稳定。
猜你喜欢
  • 2021-11-11
  • 2018-06-07
  • 1970-01-01
  • 1970-01-01
  • 2020-06-20
  • 2017-12-31
  • 2021-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多