SwiftUI减少列表行之间的间距至零

3

我想把列表中的行距减少到零。

我试过减少填充,但没有成功。 设置 ´.environment(.defaultMinListRowHeight, 0)´ 对我很有帮助。

struct ContentView: View {
  @State var data : [String] = ["first","second","3rd","4th","5th","6th"]

  var body: some View {
    VStack {
      List {
        ForEach(data, id: \.self)
        { item in
          Text("\(item)")
          .padding(0)
          //.frame(height: 60)
          .background(Color.yellow)
        }
        //.frame(height: 60)
        .padding(0)
        .background(Color.blue)
      }
      .environment(\.defaultMinListRowHeight, 0)
      .onAppear { UITableView.appearance().separatorStyle = .none }
      .onDisappear { UITableView.appearance().separatorStyle = .singleLine }
    }
  }
}

将 ´separatorStyle´ 更改为 ´.none´ 只会移除线条但是空间仍然存在。
列表行或者行之间的分隔符是否有额外的 ´hidden´ 视图?如何控制它们?
使用 ScrollView 代替 List 是否是一个好的解决方案?
ScrollView(.horizontal, showsIndicators: true)
        {
      //List {
        ForEach(data, id: \.self)
        { item in
          HStack{
          Text("\(item)")
            Spacer()
          }

它也适用于大型数据集吗?


3
上一个问题 - 绝对不是吗?在上一个之前的问题 - 可能(没有缓存,没有重用,所有内容都在开始时构建)。在初始状态下 - 它需要考虑... - Asperi
1
我个人更喜欢使用ScrollView,特别是在macOS上。Asperi的回答可能会解决你的问题。使用ScrollView更加灵活,但要准备好处理许多手势方面的次要问题。我希望在SwiftUI的下一个版本中ListStyle将更具可配置性(也许会提供一些公共API)。 - user3441734
3个回答

7

实际上不足为奇-.separatorStyle = .none工作正常。我想你将文本背景与单元格背景混淆了,它们由不同的修饰符更改。请查找以下经过测试和工作的代码(Xcode 11.2 / iOS 13.2)

演示

struct ContentView: View {
  @State var data : [String] = ["first","second","3rd","4th","5th","6th"]

  var body: some View {
    VStack {
      List {
        ForEach(data, id: \.self)
        { item in
          Text("\(item)")
            .background(Color.yellow) // text background
            .listRowBackground(Color.blue) // cell background
        }
      }
      .onAppear { UITableView.appearance().separatorStyle = .none }
      .onDisappear { UITableView.appearance().separatorStyle = .singleLine }
    }
  }
}

更新:

无法避免黄色文本之间出现蓝色空间吗?

从技术上讲,是可以的,但是为了演示目的,使用了硬编码的值,调整一些并不困难,但要动态计算可能具有挑战性……无论如何,这里是示例:

demo2

需要使用堆栈进行压缩、内容填充以增加阻力,以及限制环境的组合。

  List {
    ForEach(data, id: \.self)
    { item in
        HStack {                                 // << A
          Text("\(item)")
            .padding(.vertical, 2)               // << B
        }
        .listRowBackground(Color.blue)
        .background(Color.yellow)
        .frame(height: 12)                       // << C
    }
  }
  .environment(\.defaultMinListRowHeight, 12)    // << D

1
不错!你有想法如何在 macOS 上解决相同的问题吗? - user3441734
谢谢 - 但是无法避免黄色文本之间的蓝色空间吗? - mica
1
@mica,简而言之 - 可能是可以的,但是...请查看答案中的更新部分。 - Asperi
动态内容怎么办(行高未知)?我更新了我的答案,以展示为什么我更喜欢ScrollView... - user3441734

3

我用简单的 (iOS) SwiftUI 方式实现:

struct ContentView: View {
    
    init() {
        UITableView.appearance().separatorStyle = .none
    }
    
    var body: some View {
        List {
            ForEach(0..<10){ item in
                Color.green
            }
            .listRowInsets( EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) )
        }
    }
}

这不是SwiftUI的方式。这需要导入UIKit,在非iOS设备(macOS)上会有一些小问题。 - Tycho Pandelaar

2
"减少行间距真的很棘手,请尝试"
struct ContentView: View {
    @State var data : [String] = ["first","second","3rd","4th","5th","6th"]

    var body: some View {
        VStack {
            ScrollView {
                ForEach(data, id: \.self) { item in
                    VStack(alignment: .leading, spacing: 0) {
                        Color.red.frame(height: 1)
                        Text("\(item)").font(.largeTitle)
                            .background(Color.yellow)
                    }.background(Color.green)
                    .padding(.leading, 10)
                    .padding(.bottom, -25)
                    .frame(maxWidth: .infinity)
                }
            }
        }
    }
} 

它使用ScrollView而不是List和负填充。

enter image description here

我没有找到任何基于List的解决方案,我们必须要求苹果发布xxxxStyle协议和底层结构。
更新
这个负的padding值怎么样?肯定取决于我们行内容的高度,不幸的是,还取决于SwiftUI的布局策略。让我们尝试一些更动态的内容!(我们使用零填充来演示需要解决的问题)
struct ContentView: View {
    @State var data : [CGFloat] = [20, 30, 40, 25, 15]

    var body: some View {
        VStack {
            ScrollView {
                ForEach(data, id: \.self) { item in
                    VStack(alignment: .leading, spacing: 0) {
                        Color.red.frame(height: 1)
                        Text("\(item)").font(.system(size: item))
                            .background(Color.yellow)
                    }.background(Color.green)
                    .padding(.leading, 10)
                    //.padding(.bottom, -25)
                    .frame(maxWidth: .infinity)
                }
            }
        }
    }
}

enter image description here

显然,行间距不是固定值!我们必须为每一行分别计算它。
下一个代码片段展示了基本思路。我使用了全局字典(用于存储每一行的高度和位置),并尽量避免使用高阶函数和/或一些高级的SwiftUI技术,以便更容易理解策略。所需的填充仅在.onAppear闭包中计算一次。
import SwiftUI

var _p:[Int:(CGFloat, CGFloat)] = [:]

struct ContentView: View {
    @State var data : [CGFloat] = [20, 30, 40, 25, 15]
    @State var space: [CGFloat] = []

    func spc(item: CGFloat)->CGFloat {
        if let d = data.firstIndex(of: item) {
            return d < space.count ? space[d] : 0
        } else {
            return 0
        }
    }

    var body: some View {
        VStack {
            ScrollView {
                ForEach(data, id: \.self) { item in
                    VStack(alignment: .leading, spacing: 0) {
                        Color.red.frame(height: 1)
                        Text("\(item)")
                            .font(.system(size: item))
                            .background(Color.yellow)
                    }
                    .background(
                        GeometryReader { proxy->Color in
                            if let i = self.data.firstIndex(of: item) {
                                _p[i] = (proxy.size.height, proxy.frame(in: .global).minY)
                            }
                            return Color.green
                        }
                    )
                    .padding(.leading, 5)
                    .padding(.bottom, -self.spc(item: item))

                    .frame(maxWidth: .infinity)
                }.onAppear {
                    var arr:[CGFloat] = []
                    _p.keys.sorted(by: <).forEach { (i) in
                        let diff = (_p[i + 1]?.1 ?? 0) - (_p[i]?.1 ?? 0) - (_p[i]?.0 ?? 0)
                        if diff < 0 {
                            arr.append(0)
                        } else {
                            arr.append(diff)
                        }
                    }
                    self.space = arr
                }
            }
        }
    }
}

运行我得到的代码

enter image description here


谢谢:您是否像@Asperi一样在处理大型数据集时遇到了相同的问题(没有缓存,没有重用,所有内容都在开始时构建)? - mica
1
在代码片段中,您可以看到一种想法,ForEach用于根据需要构建动态内容,我没有看到任何区别...最困扰的是要实现与列表行默认相同的手势。最后,ScrollView解决方案甚至可在macOS上使用。您必须做出决定...没有什么是免费的! - user3441734
1
@mica,请查看更新的示例,其中行内容更加动态。 - user3441734

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