15

我在动态更改依赖于元素计数的列表高度时遇到了一些麻烦。

我尝试了这个解决方案,但没有奏效。

List {
    ForEach(searchService.searchResult, id: \.self) { item in
        Text(item)
        .font(.custom("Avenir Next Regular", size: 12))
    }
}.frame(height: CGFloat(searchService.searchResult.count * 20))
4

4 回答 4

20

TL;博士

这不是 SwiftUI 的设计者希望你使用列表的方式。要么你必须想出一个在未来可能会崩溃的 hacky 解决方案(见下文),要么使用列表以外的东西。

背景

SwiftUI 往往有两种类型的 Views

  1. 这些设计易于修改和组合,提供无限的可定制性以获得独特的外观和感觉。
  2. 那些旨在为某种类型的交互提供标准、一致的感觉的工具,无论它们在什么应用程序中使用。

类型 1 的一个示例是文本。您可以更改字体大小、粗细、字体、颜色、背景、填充等。它专为您修改而设计。

类型 2 的一个示例是 List。你不能直接控制行高,你不能改变视图周围的填充,你不能告诉它只显示这么多行等等。他们不希望它是非常可定制的,因为每个应用程序的列表的行为会有所不同,违背了标准控件的目的。

List 旨在用尽可能多的行填充整个父视图,即使它们是空的或仅部分显示在屏幕上(如果一次显示太多则滚动)。

你的问题

您遇到的问题是因为 List 的大小不会以任何方式影响其行的大小。SwiftUI 不关心行数是否太多或太少而无法适应您的首选大小;它会根据内容愉快地调整其行的大小,即使这意味着它们没有全部显示或者显示了空行。

如果您确实需要根据父项的大小调整行的大小,则应该使用 VStack。如果需要滚动,则需要将 VStack 包装在 ScrollView 中。

哈克解决方案

如果您仍然坚持使用列表,则必须执行以下操作:

struct ContentView: View {

    @State private var textHeight: Double = 20
    let listRowPadding: Double = 5 // This is a guess
    let listRowMinHeight: Double = 45 // This is a guess
    var listRowHeight: Double {
        max(listRowMinHeight, textHeight + 2 * listRowPadding)
    }

    var strings: [String] = ["One", "Two", "Three"]

    var body: some View {
        VStack {
            HStack {
                Text(String(format: "%2.0f", textHeight as Double))
                Slider(value: $textHeight, in: 20...60)
            }
                VStack(spacing: 0) {
                    Color.red
                    List {
                        ForEach(strings, id: \.self) { item in
                            Text(item)
                                .font(.custom("Avenir Next Regular", size: 12))
                                .frame(height: CGFloat(self.textHeight))
                                .background(Color(white: 0.5))
                        }
                    }
                    // Comment out the following line to see how List is expected to work
                    .frame(height: CGFloat(strings.count) * CGFloat(self.listRowHeight))
                    Color.red
            }.layoutPriority(1)
        }
    }
}

滑块用于显示列表行高如何随其子视图的高度而变化。您必须手动选择listRowPaddinglistRowMinHeight获得最符合您期望的外观。如果 Apple 改变了 List 的外观(更改填充、最小行高等),您将不得不记得返回并手动调整这些值。

于 2019-09-23T15:03:33.577 回答
15

自我尺寸List

如果你想一次List显示它的内容,这意味着你不需要回收功能(列表的关键功能),所以你只需要不使用List!相反,您可以ForEach直接使用,然后它会根据内容自行调整大小:

ForEach(searchService.searchResult, id: \.self) { item in
    VStack(alignment: .leading) {
        Text(item).font(.custom("Avenir Next Regular", size: 12))
        Divider()
    }.padding(.horizontal, 8)
}

您可以根据需要更改所有尺寸和间距

请注意,您可以LazyVStackiOS 14开始使用以使其延迟加载并提高其性能。

于 2019-11-21T08:33:49.680 回答
3

从 iOS 14 开始,您可以LazyVStack使用List. 列表似乎跨越了整个父视图高度,与行高或计数无关。

LazyVStack {
    ForEach(searchService.searchResult, id: \.self) { item in
        Text(item)
        .font(.custom("Avenir Next Regular", size: 12))
    }
}.frame(height: 

其他解决方案是.frame(height: )基于rowCount*rowHeight或其他在 List 上设置GeometryReader -> geometry.size.height

于 2021-04-23T11:31:49.750 回答
0

SwiftUi 已经进化。这是SwiftUI 3的一个简单明了的答案:https ://stackoverflow.com/a/65769005/4514671

于 2022-02-19T21:02:48.903 回答