You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UIStackView内嵌UIScrollView高度为0不显示问题排查

问题成因

垂直布局的UIStackView计算arrangedSubview排布尺寸时,仅依赖子视图的固有内容尺寸或显式约束。将原水平子栈包裹进UIScrollView后出现高度为0的问题,核心原因有三点:

  • UIScrollView本身无固有内容尺寸,其contentSize由内部子视图约束决定,但不会将内部内容的高度反向传递给上层父视图,外层垂直栈无法自动推算UIScrollView的占据高度,默认分配高度为0。
  • 代码存在约束遗漏:仅给最外层containerStack关闭了translatesAutoresizingMaskIntoConstraints,scrollView和内部scrolledStack未关闭该属性,手写约束会与系统自动生成的约束冲突。
  • 未给scrolledStack设置axis = .horizontal,与原本的水平排布需求不符;且原约束将scrolledStack宽度绑定为和scrollView相等,即便视图正常显示也无法实现水平滚动效果。
修复方案

按照以下步骤调整代码即可正常显示并实现水平滚动:

  1. 给scrollView、scrolledStack添加translatesAutoresizingMaskIntoConstraints = false,保证手写约束生效。
  2. 给scrolledStack设置水平排布属性:scrolledStack.axis = .horizontal,匹配原本的布局逻辑。
  3. 替换UIScrollView内部约束的绑定对象:滚动内容边距绑定scrollView.contentLayoutGuide,内部栈的高度绑定scrollView.frameLayoutGuide,去掉原代码中scrolledStack与scrollView等宽的约束,让内容宽度自适应撑开,实现水平滚动。
  4. 给UIScrollView添加明确的高度约束,告知外层垂直栈它的排布尺寸,可根据业务需求选择固定高度、与其他子视图等高、按比例适配容器高度任意一种规则。
  5. (可选调整)如果希望上下两个子视图均分垂直容器的高度,可将containerStack.distribution修改为.fillEqually,无需额外加高度约束即可实现上下各占一半的效果。

修正后的核心代码参考:

func initViews(){
    let containerStack = UIStackView()
    addSubview(containerStack)
    containerStack.axis = .vertical
    // 若要上下子视图均分高度可改为 .fillEqually
    containerStack.distribution = .equalCentering
    containerStack.isLayoutMarginsRelativeArrangement = true
    containerStack.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    containerStack.translatesAutoresizingMaskIntoConstraints = false
    
    
    let scrollView = UIScrollView()
    // 关闭自动约束转换
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.showsHorizontalScrollIndicator = true
    
    let scrolledStack = UIStackView()
    // 关闭自动约束转换
    scrolledStack.translatesAutoresizingMaskIntoConstraints = false
    // 设置水平排布
    scrolledStack.axis = .horizontal
    
    containerStack.addArrangedSubview(scrollView)
    scrollView.addSubview(scrolledStack)
    scrolledStack.distribution = .fill
    scrolledStack.isLayoutMarginsRelativeArrangement = true
    scrolledStack.layoutMargins = UIEdgeInsets(top: 20, left: 30, bottom: 20, right: 30)
    
    // 绑定滚动内容边距到contentLayoutGuide
    scrolledStack.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor).isActive = true
    scrolledStack.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor).isActive = true
    scrolledStack.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor).isActive = true
    scrolledStack.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor).isActive = true
    // 内部栈高度与scrollView可视高度一致,保证垂直方向不滚动
    scrolledStack.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor).isActive = true
    
    // 给scrollView添加高度约束,这里以固定高度200为例,可替换为其他高度规则
    scrollView.heightAnchor.constraint(equalToConstant: 200).isActive = true
    
    
    let otherStack = UIStackView()
    otherStack.translatesAutoresizingMaskIntoConstraints = false
    otherStack.axis = .horizontal
    containerStack.addArrangedSubview(otherStack)
    otherStack.distribution = .equalCentering
    otherStack.isLayoutMarginsRelativeArrangement = true
    otherStack.layoutMargins = UIEdgeInsets(top: 20, left: 30, bottom: 0, right: 30)
    
    
    containerStack.topAnchor.constraint(equalTo: topAnchor).isActive = true
    containerStack.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    containerStack.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
    containerStack.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
    
    
    for number in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]{
        let text = UITextView()
        text.font = UIFont.boldSystemFont(ofSize: 14)
        text.text = number
        text.isScrollEnabled = false
        text.backgroundColor = .clear
        
        scrolledStack.addArrangedSubview(text)
    }
    for number in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]{
        let text = UITextView()
        text.font = UIFont.boldSystemFont(ofSize: 14)
        text.text = number
        text.isScrollEnabled = false
        text.backgroundColor = .clear
        
        otherStack.addArrangedSubview(text)
    }
}

注意:UIScrollView 从iOS 11开始引入contentLayoutGuide和frameLayoutGuide,约束内部滚动内容时优先绑定contentLayoutGuide,控制内部内容和滚动视图自身尺寸关系时绑定frameLayoutGuide,可以避免很多滚动区域计算错误的问题。

内容的提问来源于stack exchange,提问作者Josemafuen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:51:29