SwiftUI将列表中的行间距减小为空

时间:2020-03-01 10:17:12

标签: swiftui swiftui-list

我想将列表中的行距减少为空。

我减少填充的尝试没有用。 设置“ .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”只会删除行,但留有空格。
列表行或行之间的分隔符是否有额外的“隐藏”视图? 如何控制呢?

会使用ScrollView而不是List的好方法吗?

ScrollView(.horizontal, showsIndicators: true)
        {
      //List {
        ForEach(data, id: \.self)
        { item in
          HStack{
          Text("\(item)")
            Spacer()
          }

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

3 个答案:

答案 0 :(得分:3)

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

demo

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 :(得分: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的解决方案,我们不得不要求Apple发布xxxxStyle协议和底层结构。

更新

该负填充值如何?当然,这取决于行内容的高度,不幸的是取决于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

答案 2 :(得分:0)

我这样做很简单:

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) )
        }
    }
}