SwiftUI布局需求:空间充足时用fixedSize,不足时VStack自动收缩
SwiftUI 实现自适应宽度的VStack
需求:构建一个宽度等于其内部最宽元素的VStack——水平空间充足时,保持这个最小必要宽度;空间不足(比如窄屏)时,内部内容自动收缩适配。
示例代码:
VStack { HStack { Text("title1") Spacer() Text("title2") Spacer() Text("title3") } HStack { Text("fo0o0o0o0o0o0o0o0oo0o0o0") Spacer() Text("fo0o0o0o0o") Spacer() Text("fo0") } HStack { Text("fo0o0o0o0o") Spacer() Text("fo0o") Spacer() Text("fo0") } }.fixedSize()
当前问题:加了fixedSize()后,内容不会收缩直接超出屏幕;不加的话,Spacer会占满所有水平空间,导致VStack拉得太宽。而且内容是动态的,没法硬写宽度。怎么实现「空间够就用fixedSize,不够就自动收缩」的逻辑?
解决方案:用PreferenceKey + GeometryReader 动态判断
核心思路是先算出所有子视图的理想宽度最大值,再和当前可用空间对比,决定是否启用fixedSize。
- 定义PreferenceKey用来收集子视图宽度
struct ViewWidthKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = max(value, nextValue()) } }
- 修改原布局,捕获每个HStack的理想宽度,并动态适配
GeometryReader { geometry in VStack { HStack { Text("title1") Spacer() Text("title2") Spacer() Text("title3") } .background( GeometryReader { proxy in Color.clear.preference(key: ViewWidthKey.self, value: proxy.size.width) } ) HStack { Text("fo0o0o0o0o0o0o0o0oo0o0o0") Spacer() Text("fo0o0o0o0o") Spacer() Text("fo0") } .background( GeometryReader { proxy in Color.clear.preference(key: ViewWidthKey.self, value: proxy.size.width) } ) HStack { Text("fo0o0o0o0o") Spacer() Text("fo0o") Spacer() Text("fo0") } .background( GeometryReader { proxy in Color.clear.preference(key: ViewWidthKey.self, value: proxy.size.width) } ) } .onPreferenceChange(ViewWidthKey.self) { idealWidth in self.idealVStackWidth = idealWidth } .fixedSize(horizontal: geometry.size.width > idealVStackWidth, vertical: false) } @State private var idealVStackWidth: CGFloat = 0
代码解释
ViewWidthKey用来收集所有HStack的宽度,取最大值作为VStack的理想宽度- 每个HStack背后加个透明的
GeometryReader,把自己的宽度通过PreferenceKey传递出去 - 外层的
GeometryReader获取当前可用的水平空间 - 最后通过比较可用空间和理想宽度,动态设置
fixedSize(horizontal:)的布尔值:空间够就启用fixedSize(保持理想宽度),不够就关闭(让内容收缩)
这样就能实现空间充足时保持最小宽度,空间不足时自动收缩的效果,完全适配动态内容。
内容的提问来源于stack exchange,提问作者Elektronenhirn
相关产品推荐
相关产品推荐

