ScrollView内的ForEach不占据整个宽度。

5

我正在尝试使用SwiftUI重新创建我的当前应用程序的用户界面,但这要比我最初想象的要困难得多。

我想要实现类似卡片的单元格,并在它们的背后添加一些背景。我发现List不支持这一点,至少目前还没有。 List非常有限-它不允许你去除单元格分隔线。

因此,我转而在ScrollView内部使用ForEach。我想这不是适合长表格的生产环境中使用的东西,但现在应该可以工作。我的问题是ForeEach视图没有利用ScrollView提供的全部宽度。我可以设置.frame(...)修饰符,但这将需要硬编码宽度,我绝对不想这样做。

有什么想法可以强制VStack占用ScrollView的整个宽度吗?我尝试过不使用VStackForEach,但是它也有同样的问题。似乎ScrollView(父视图)会“告诉”其子视图(VStack)它的框架大小比实际的ScrollView框架还小。基于这些信息,子视图构建它们的布局和大小。

以下是我的当前结果:

以下是代码:

struct LandmarkList : View {
    var body: some View {
        NavigationView {
            ScrollView() {
                VStack {
                    Spacer().frame(height: 160)
                    ForEach(landmarkData) { landmark in
                        LandmarkRow(landmark: landmark).padding([.leading, .trailing], 16)
                    }
                }.scaledToFill()
                .background(Color.pink)
            }
            .background(Color.yellow)
            .edgesIgnoringSafeArea(.all)
            .navigationBarTitle(Text("Landmarks"))

        }
    }
}

struct LandmarkRow : View {
    var landmark: Landmark

    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text(landmark.name).font(.title)
                Text("Subtitle")
                    .font(.callout)
                    .color(.gray)
            }
            Spacer()
            Text("5 mi")
                .font(.largeTitle)
            }.frame(height: 80)
            .padding()
            .background(Color.white)
            .cornerRadius(16)
            .clipped()
            .shadow(radius: 2)
    }
}

你可以在 HStack 中使用 Spacer() 在底部和顶部添加 VStack,这样它将占据整个屏幕。不确定这是否适用于 ScrollView。 - Prashant Tukadiya
@PrashantTukadiya 如果我将 HStackVStackSpacer 结合使用,单元格将不会变成全宽。 在 Building Custom Views 演讲中,苹果工程师解释了大小调整的原理。从我在这里看到的情况来看 - ScrollView 并没有传递其自身的大小,而是传递了一些 ScrollViewContent 的大小(这不是实际名称),该大小比 ScrollView 本身要小。将 ScrollView 替换为另一个视图可以解决问题,但我会失去滚动功能。 - OgreSwamp
2个回答

3

我遇到了同样的问题,目前我找到的唯一解决方法是修复ScrollView和内容视图宽度,这样您在内容视图中添加的每个子视图都将被居中。

我创建了一个简单的包装器,以初始参数形式接受宽度。

struct CenteredList<Data: RandomAccessCollection, Content: View>: View where Data.Element: Identifiable {

    public private(set) var width: Length
    private var data: Data
    private var contentBuilder: (Data.Element.IdentifiedValue) -> Content

    init(
        width: Length = UIScreen.main.bounds.width,
        data: Data,
        @ViewBuilder content: @escaping (Data.Element.IdentifiedValue) -> Content)
    {
        self.width = width
        self.data = data
        self.contentBuilder = content
    }

    var body: some View {
        ScrollView {
            VStack {
                ForEach(data) { item in
                    return self.contentBuilder(item)
                }.frame(width: width)
            }
            .frame(width: width)
        }
        .frame(width: width)
    }
}

默认情况下,它使用屏幕宽度 (UIScreen.main.bounds.width)。

它的工作方式类似于List视图:

var body: some View {
    TileList(data: 0...3) { index in
        HStack {
            Text("Hello world")
            Text("#\(index)")
         }
    }
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接