ScrollView内图片铺满可用宽度:无需移出GeometryReader的实现方案
问题描述
我希望将图片扩展至视图的全部可用宽度,为此使用了.frame(width: geometry.size.width),但当GeometryReader处于ScrollView内部时该方法失效。我知晓需将GeometryReader置于ScrollView外才能生效,但无法为此重构代码。请问是否存在方法,能让图片在ScrollView内时仍利用视图的全部可用宽度?注:应用不同区域的可用空间尺寸存在差异。
附带代码:
import SwiftUI struct UploadHustleCamera: View { var body: some View { ScrollView { HStack { RoundedRectangle(cornerRadius: 5)//some random width Text("hello")//some random text Spacer() //does not work since in scroll view GeometryReader(content: { geometry in KFImage(URL(string: "https://buffer.com/cdn-cgi/image/w=1000,fit=contain,q=90,f=auto/library/content/images/size/w1200/2023/09/instagram-image-size.jpg")) .resizable() .aspectRatio(contentMode: .fit) .frame(width: geometry.size.width) .cornerRadius(18) }) } } } }
解决方案
以下几种方法可以解决ScrollView内图片占满可用宽度的问题,无需重构将GeometryReader移到外部:
方法1:通过外部GeometryReader传递尺寸
在ScrollView外层套一个GeometryReader获取整体可用宽度,再计算图片能使用的宽度(减去左侧元素和间距的占用):
import SwiftUI struct UploadHustleCamera: View { @State private var imageAvailableWidth: CGFloat = 0 var body: some View { GeometryReader { outerGeo in ScrollView { HStack { RoundedRectangle(cornerRadius: 5) .frame(width: 40, height: 40) // 给左侧矩形明确尺寸 Text("hello") Spacer() KFImage(URL(string: "https://buffer.com/cdn-cgi/image/w=1000,fit=contain,q=90,f=auto/library/content/images/size/w1200/2023/09/instagram-image-size.jpg")) .resizable() .aspectRatio(contentMode: .fit) .frame(width: imageAvailableWidth) .cornerRadius(18) } .onAppear { // 根据实际布局调整左侧元素总宽度和间距值 let leftContentWidth: CGFloat = 40 + 50 + 32 // 矩形+文本+默认左右间距 imageAvailableWidth = outerGeo.size.width - leftContentWidth } } } } }
方法2:强制HStack适应父容器宽度
给HStack添加frame(maxWidth: .infinity)和fixedSize(horizontal: false, vertical: true),让HStack强制占满ScrollView的父容器宽度,内部的GeometryReader就能正确获取可用宽度:
import SwiftUI struct UploadHustleCamera: View { var body: some View { ScrollView { HStack { RoundedRectangle(cornerRadius: 5) .frame(width: 40, height: 40) Text("hello") Spacer() GeometryReader { geometry in KFImage(URL(string: "https://buffer.com/cdn-cgi/image/w=1000,fit=contain,q=90,f=auto/library/content/images/size/w1200/2023/09/instagram-image-size.jpg")) .resizable() .aspectRatio(contentMode: .fit) .frame(width: geometry.size.width) .cornerRadius(18) } } .frame(maxWidth: .infinity) .fixedSize(horizontal: false, vertical: true) } } }
方法3:用PreferenceKey传递容器宽度
自定义PreferenceKey来传递ScrollView父容器的宽度,内部图片直接使用该宽度计算可用空间:
import SwiftUI // 自定义偏好键传递宽度 struct ContainerWidthKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } } struct UploadHustleCamera: View { @State private var containerWidth: CGFloat = 0 var body: some View { ScrollView { HStack { RoundedRectangle(cornerRadius: 5) .frame(width: 40, height: 40) Text("hello") Spacer() KFImage(URL(string: "https://buffer.com/cdn-cgi/image/w=1000,fit=contain,q=90,f=auto/library/content/images/size/w1200/2023/09/instagram-image-size.jpg")) .resizable() .aspectRatio(contentMode: .fit) .frame(width: containerWidth - 40 - 50 - 32) .cornerRadius(18) } } .background( GeometryReader { geo in Color.clear .preference(key: ContainerWidthKey.self, value: geo.size.width) } ) .onPreferenceChange(ContainerWidthKey.self) { containerWidth = $0 } } }
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

