SwiftUI - 取决于元素计数的可调整大小的列表高度

Posted

技术标签:

【中文标题】SwiftUI - 取决于元素计数的可调整大小的列表高度【英文标题】:SwiftUI - Resizable List height that dependent on an element count 【发布时间】:2019-09-23 10:35:59 【问题描述】:

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

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

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

【问题讨论】:

因此,您的想法是将列表高度(列表视图本身的高度)设置为每个项目 20 像素。如果它有效,在这种情况下它就不能滚动(因为所有元素都有足够的空间)。那为什么不直接使用 VStack 呢?另一方面,如果您的目标是为列表中的项目设置大小,我假设您需要设置项目的大小,而不是列表。不过我对 SwiftUI 不是很熟悉。 不,我不需要更改行高。我需要更改列表视图的高度,这取决于元素计数。例如,如果我在数组中只有一个元素 -> 我需要显示只有一行的列表,而这一行将是该列表的整个框架 那么,如果你不打算使用滚动,有什么特别的原因让你想使用List 而不是VStack 您的解决方案应该有效 - 您的 searchService 是否标记为 @ObservedObject?而searchResult 标记为@Published? @Abjox 考虑为MKLocalSearchCompleter 添加一些代理对象并删除NSObject - 它应该开始工作:) 【参考方案1】:

TL;DR

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

背景

SwiftUI 往往有两种视图

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

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

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

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 的外观(改变内边距、最小行高等),您必须记得返回并手动调整这些值。

【讨论】:

【参考方案2】:

自尺码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)

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

请注意您可以使用 iOS 14 中的 LazyVStack 使其延迟加载并提高其性能。

【讨论】:

天啊。谢谢!列表给我带来了无穷无尽的麻烦——如果你在子视图中使用“列表”,那么你的身高会缩小到零。阅读大量尝试使用 GeometryReader 获取子内容大小的黑客,但无法使其正常工作。从 List 切换到 ForEach 立即为我修复了它。谢谢。 List 的其他主要功能之一是无需任何代码即可立即拥有Editmode。使用 VStack/ScrollView 时如何存档? 请注意,此答案丢失了 List 的重要部分,即它不会立即渲染所有内容。如果您想在包含数百个项目的列表上执行此操作,滚动时会出现性能问题。 @iSpain17 self size list 似乎不需要我在回答开头提到的那种性能,因为更多的数据导致它没有。不再是自我大小。但是ios 14 开始,您可以改用 LazyVStack,这正是您要寻找的东西。 我认为 OP 想要一些缩小到阈值以下并滚动到阈值以上的东西。我正在寻找类似的东西,因此,您只需使用 .frame(maxHeight:xxx) 和 xxx 由(屏幕或父视图高度的百分比)或(elements.height * thresholdElementCount)中的较小者计算.【参考方案3】:

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

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

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

【讨论】:

【参考方案4】:

SwiftUi 已经进化。以下是 SwiftUI 3 的简单答案:https://***.com/a/65769005/4514671

【讨论】:

以上是关于SwiftUI - 取决于元素计数的可调整大小的列表高度的主要内容,如果未能解决你的问题,请参考以下文章

粘性标题不适用于 Primeng 中可调整大小的列。?

如何使 html 表格列可调整大小?

带有可调整大小的列的 Tailwind 两列布局

如何使用 jQuery UI 使 datatables.js 的列可调整大小

如何使用纯 Javascript 使 HTML 元素可调整大小?

如何使用纯 Javascript 使 HTML 元素可调整大小?