如何在UIScrollView中垂直居中UIStackView并保留滚动功能?
解决UIStackView在UIScrollView中垂直居中且保持滚动的问题
兄弟,我太懂这种iOS Auto Layout和ScrollView死磕的憋屈了!Android里确实三下五除二就能搞定,但iOS的ScrollView约束逻辑有个坑——它的内容大小是靠内部视图的约束撑起来的,而且要兼顾居中+滚动,得把优先级和约束对象搞对才行。
先说说你当前做法的问题:你给ScrollView加了全屏约束(scroll.FullSizeOf(View))和禁用自动转译约束,这部分没问题,但你没给内部的StackView设置正确的约束组合,导致要么没法居中,要么滚动失效。
下面是具体的解决步骤,用Swift代码举例(OC逻辑完全一致,只是语法不同):
核心约束逻辑
要实现“内容少时居中,内容多时滚动”,关键是给StackView设置优先级不同的约束组合,同时区分ScrollView的frameLayoutGuide(ScrollView本身的框架)和contentLayoutGuide(内容区域的框架):
// 先确保ScrollView和StackView都禁用自动转译约束 scroll.translatesAutoresizingMaskIntoConstraints = false let stackView = UIStackView() stackView.translatesAutoresizingMaskIntoConstraints = false stackView.axis = .vertical stackView.alignment = .center // 根据你的需求调整,比如.fill也可以 stackView.spacing = 16 // 添加视图层级 view.addSubview(scroll) scroll.addSubview(stackView) // 激活约束 NSLayoutConstraint.activate([ // 1. ScrollView和父View的全屏约束,这部分你已经做了 scroll.leadingAnchor.constraint(equalTo: view.leadingAnchor), scroll.trailingAnchor.constraint(equalTo: view.trailingAnchor), scroll.topAnchor.constraint(equalTo: view.topAnchor), scroll.bottomAnchor.constraint(equalTo: view.bottomAnchor), // 2. StackView和ScrollView内容区域的约束:左右对齐,上下不超出 stackView.leadingAnchor.constraint(equalTo: scroll.contentLayoutGuide.leadingAnchor), stackView.trailingAnchor.constraint(equalTo: scroll.contentLayoutGuide.trailingAnchor), stackView.topAnchor.constraint(greaterThanOrEqualTo: scroll.contentLayoutGuide.topAnchor), stackView.bottomAnchor.constraint(lessThanOrEqualTo: scroll.contentLayoutGuide.bottomAnchor), // 3. 强制StackView宽度和ScrollView一致,避免横向滚动 stackView.widthAnchor.constraint(equalTo: scroll.frameLayoutGuide.widthAnchor), // 4. 垂直居中约束,优先级设为次高(低于上下不超出的约束) stackView.centerYAnchor.constraint(equalTo: scroll.frameLayoutGuide.centerYAnchor).priority = .defaultHigh ])
为什么这样能行?
- 当StackView的总高度小于ScrollView的高度时,
centerY约束会生效,把StackView牢牢固定在垂直居中位置,而top >=和bottom <=的约束只是保证它不会超出ScrollView的边界; - 当StackView的总高度大于ScrollView的高度时,
top >=和bottom <=的约束会自动撑开ScrollView的内容区域(contentSize),让ScrollView可以正常滚动,此时centerY约束因为优先级更低,会被自动忽略,不会干扰滚动功能。
补充注意点
- 如果你用的是第三方封装的
EnableAutoLayout()和FullSizeOf(View),要确认它们确实正确设置了translatesAutoresizingMaskIntoConstraints = false和四边约束; - StackView的
distribution属性尽量设为.fill,避免内部视图的尺寸影响整体居中效果; - 不要给StackView设置固定高度,否则会导致滚动失效(除非你明确需要固定高度,但那样就没必要用ScrollView了)。
内容的提问来源于stack exchange,提问作者CarLoOSX
相关产品推荐
相关产品推荐

