如何创建子视图对齐方式不同的iOS UIStackView并解决约束冲突
约束冲突根因
- 报错中
UIStackView.width == 0指的是承载四个按钮的内层栈视图。当垂直size class为compact时,外层栈切换为水平排布,此时外层按比例分配子视图宽度,而内层栈因为开启了center对齐模式,无法通过内部按钮的宽度算出自适应的intrinsic content size,默认返回宽度0,被分配到0宽度的可用空间 - 冲突触发逻辑:内层栈既要满足0宽度的分配要求,又要通过居中对齐定位300宽的按钮,两套约束逻辑无法共存,系统就会自动断裂按钮的300宽约束做兜底,哪怕视觉上看起来暂时正常,后续只要屏幕尺寸变化就会出现布局错位
- 普通垂直模式下没报错,是因为此时内层栈被外层水平方向撑满了整个屏幕宽度,足够放下300宽的居中按钮,没有触发宽度不足的冲突
无冲突的实现步骤
- 第一步:给内层按钮栈本身添加宽度=300的固定约束,删除之前给每个按钮单独添加的width=300约束。这样系统不需要自动计算栈的自身宽度,从根源上避免它被分配到0宽度
内层栈保持垂直排布、distribution=fillEqually,alignment设为fill,这样四个按钮会自动撑满300宽的栈容器,不需要单独给按钮设宽度 - 第二步:把外层栈的
distribution从fillProportionally改为fill。这种模式下,外层会把所有可用空间分配给两个子视图,不会按比例压缩子视图宽度,从机制上避免子视图宽度被不合理分配到0
因为外层栈在垂直排布时需要满足「图片占满全宽、300宽按钮组居中」的混合对齐要求,单独靠栈的全局alignment参数无法实现,所以给两个子视图单独加对齐约束:- 给图片视图加leading、trailing约束到外层栈的leading、trailing,保证图片撑满整个外层的水平宽度
- 给300宽的内层按钮栈加centerX约束到外层栈的centerX,保证按钮组不管屏幕宽度多少,永远水平居中,不会因为外层fill对齐贴到左边
- 第三步:调整图片视图的优先级设置
图片的horizontalHuggingPriority和verticalHuggingPriority都设为250(比系统默认值稍低),保证图片会优先撑满可用的宽度空间
给图片添加一个宽高比约束(值等于实际展示图片的宽高比),把约束优先级设为750:- 空间充足时,图片按自身比例自适应高度,不会拉伸变形
- 图片按比例计算出的高度过高时,这个约束会自动降级失效,图片会被限制在剩余可用空间内,用aspectFit模式展示,不会挤压按钮的垂直空间
- 第四步:保留外层栈的轴属性变体——普通垂直size class下轴为vertical,紧凑垂直size class下轴为horizontal,保证两种布局模式的切换逻辑符合需求。此时因为内层按钮栈已经是固定300宽、图片是按比例自适应的,外层水平排布时两个子视图不会因为宽度计算问题出现冲突
最终布局效果
- 普通垂直布局:图片占满屏幕可用宽度,高度按比例自适应(不超出可用空间),300宽的按钮栈水平居中,垂直方向填满图片下方的所有剩余空间
- 紧凑垂直布局:图片在左侧按可用高度自适应宽度,300宽的按钮栈在右侧剩余空间内水平居中,四个按钮垂直等距排列
- 全程无约束冲突,系统不会自动断裂你的固定宽度约束,布局不会随屏幕尺寸变化出现错位
内容的提问来源于stack exchange,提问作者Sweeper
相关产品推荐
相关产品推荐

