如何在不使用ForEach的情况下从SwiftUI中的列表中删除行分隔符?

时间:2019-06-12 01:52:51

标签: swift swiftui

我有这段代码来显示自定义行的列表。

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            List(1...10) {_ in
                CustomRow()
            }
        }
    }
}

但是,我想删除每一行上的行。我尝试不使用List,而是在ForEach内使用ScrollView,但是它完全删除了所有样式,包括其填充和边距。我只想删除这些行而已。

请帮助,谢谢。

23 个答案:

答案 0 :(得分:26)

UITableView.appearance().separatorColor = .clear出现之前在代码中的任何位置添加List应该可以。尽管此解决方案删除了​​分隔符,但请注意,所有List实例都将绑定到该样式,因为目前尚无官方方法只能删除特定实例的分隔符。您可以在onAppear中运行此代码,并在onDisappear中撤消该代码,以保持样式的不同。另请注意,此代码假定Apple使用UITableView来备份List,但这可能并非永远如此。希望他们将来会添加正式的API。

答案 1 :(得分:15)

iOS的SwiftUI的UITableView后面有一个List。因此,删除

额外的分隔符(在列表下方):

您需要一个tableFooterView并删除

所有分隔符(包括实际的分隔符):

您需要separatorStyle才能成为.none

init() {
    // To remove only extra separators below the list:
    UITableView.appearance().tableFooterView = UIView()

    // To remove all separators including the actual ones:
    UITableView.appearance().separatorStyle = .none
}

var body: some View {
    List {
        Text("Item 1")
        Text("Item 2")
        Text("Item 3")
    }
}

答案 2 :(得分:10)

签出SwiftUI-Introspect。它公开了底层的 UIKit / AppKit 视图。

仅iOS 13构建:

在这种情况下,您可以直接操作UITableView(而不必通过外观代理更改所有表视图):

    import Introspect
    :
    :
    List {
        ...
    }.introspectTableView { tableView in
         tableView.separatorStyle = .none
    }

答案 3 :(得分:6)

对于 iOS 14,你有这个:

.listStyle(SidebarListStyle()) # IOS 14

答案 4 :(得分:5)

仅iOS 13构建:

尽管这些答案在技术上都是正确的,但根据我的经验,它们会在全球范围内(整个应用程序中)影响ListForm

至少在我的应用程序中,我发现一种解决该问题的方法,是将以下代码添加到该应用程序的“主要”内容视图中:

.onAppear(perform: {
    UITableView.appearance().separatorStyle = .none
})

然后在您要使用分隔线的任何其他视图上,将其添加到ListForm视图的末尾

.onAppear(perform: {
    UITableView.appearance().separatorStyle = .singleLine
})

这似乎将单行分隔符添加到主内容视图上方的任何视图表中。同样,这都是我最近的SwiftUI经验的轶事。

根据我的经验,我只需要在我的一个“详细”视图中添加.onAppear(... = .singleLine)方法,并且在随后显示的所有视图中都显示分隔线。

编辑:由于该答案继续引起人们的注意,请注意另一点。我发布的这个解决方案并不能解决所有情况,当然在某些情况下也不能解决我的问题。我最终使用Introspect for SwiftUI来解决整个应用程序中的问题。

我希望当人们看到这篇文章时,这能消除一些困惑和沮丧。

答案 5 :(得分:4)

做类似的事情:

UITableView.appearance().separatorColor = .clear

有效,但是在很多情况下我不建议这样做。这些是全局更改-即它们将影响UITableView的所有实例。如果您有多个需要不同样式的UITableView,这将是一个问题。或者,如果您正在开发框架,则使用您的框架的客户也将继承这些更改!

一个更安全的解决方案是仅定位位于指定容器内的UITableViews。幸运的是,appearance API为我们提供了一种具体的方法:

UITableView.appearance(whenContainedInInstancesOf: [UIHostingController<YourSwiftUiViewHere>.self]).separatorColor = .clear

答案 6 :(得分:3)

我从上述答案中得到了提示。谢谢。 我的解决办法是这个。

init() {
   UITableView.appearance().tableFooterView = UIView()
}

var body: some View {
   List {
      ...
   }
}

答案 7 :(得分:3)

IOS 14

enter image description here

当前没有解决方案可以在IOS 14 beta上隐藏分隔符。

如果您不需要可编辑的List,则应在LazyVStack内使用ScrollView

但是,如果您想停留在List上。我在samwarner的Apple论坛上找到了解决方案。 https://developer.apple.com/forums/thread/651028

这是一个临时解决方案。在某些情况下,您可能需要调整插图。 这是它的实现:

struct HideRowSeparatorModifier: ViewModifier {
    static let defaultListRowHeight: CGFloat = 44
    var insets: EdgeInsets
    var background: Color
    
    init(insets: EdgeInsets, background: Color) {
        self.insets = insets
        var alpha: CGFloat = 0
        UIColor(background).getWhite(nil, alpha: &alpha)
        assert(alpha == 1, "Setting background to a non-opaque color will result in separators remaining visible.")
        self.background = background
    }
    
    func body(content: Content) -> some View {
        content
            .padding(insets)
            .frame(
                minWidth: 0, maxWidth: .infinity,
                minHeight: Self.defaultListRowHeight,
                alignment: .leading
            )
            .listRowInsets(EdgeInsets())
            .background(background)
    }
}

extension EdgeInsets {
    static let defaultListRowInsets = Self(top: 0, leading: 16, bottom: 0, trailing: 16)
}

extension View {
    func hideRowSeparator(insets: EdgeInsets = .defaultListRowInsets, background: Color = .white) -> some View {
        modifier(HideRowSeparatorModifier(insets: insets, background: background))
    }
}

最后,这是列表上的实现。您必须在列表单元格上添加.hideRowSeparator()

struct CustomRow: View {
    let text: String
    
    var body: some View {
        HStack {
            Text(self.text)
            Image(systemName: "star")
        }
    }
}

struct ContentView : View {
    @State private var fruits = ["Apple", "Orange", "Pear", "Lemon"]
    
    var body: some View {
        VStack(alignment: .leading) {
            List {
                ForEach(self.fruits, id: \.self) { str in
                    CustomRow(text: str)
                        .hideRowSeparator()
                }
            }
        }
        .padding(.top)
    }
}

答案 8 :(得分:3)

删除填充和分隔符

iOS 14.2、Xcode 12.2

ScrollView {
    LazyVStack {
        ForEach(viewModel.portfolios) { portfolio in
            PortfolioRow(item: portfolio)
        }
    }
}

这使您可以完全控制列表。 List 的当前实现不提供完全控制并包含一些问题。

答案 9 :(得分:2)

这似乎是唯一对我有用的东西。

List() {

}
.listStyle(SidebarListStyle())

答案 10 :(得分:2)

使用ScrollView吗?

代表您的列表的某些状态

@State var menuItems: [String] = ["One", "Two", "Three"]

SwiftUI内的ForEach ScrollView循环

ScrollView {
    ForEach(self.menuItems, id: \.self) { item in
        Text(item)
    }
}

答案 11 :(得分:2)

我开始在iOS14中解决此问题的项目,因为iOS 13变通办法不再起作用。它允许设置分隔符样式,分隔符颜色和分隔符插图。

隐藏列表中的分隔符

List { <content> }
    .listSeparatorStyle(.none)

显示一条带有可配置颜色和插图的分隔线

List { <content> }
    .listSeparatorStyle(.singleLine, color: .red, inset: EdgeInsets(top: 0, leading: 50, bottom: 0, trailing: 20)

https://github.com/SchmidtyApps/SwiftUIListSeparator

答案 12 :(得分:1)

所有答案都告诉您使用ScrollView(这也是我的建议)

但是如果您要使用列表并要删除分隔线。.

安装SwiftPM:https://github.com/siteline/SwiftUI-Introspect

示例:

List {
    Text("Item 1")
    Text("Item 2")
}
.introspectTableView { tableView in
    tableView.separatorStyle = .none
}

答案 13 :(得分:0)

我不确定您是否需要SwiftUI中“ UITableView”的所有功能,但是如果您只想在iOS 13或更高版本中显示视图列表,就不能这样做:

ScrollView {
    VStack(alignment: .leading) {
        ForEach(1...10) { _ in
            CustomRow()
        }
    }
}

然后添加.padding()以获得所需的边距吗?

答案 14 :(得分:0)

这是我的扩展名 ListRowExtensions ,用于隐藏列表行分隔符和自定义

import SwiftUI

// MARK: List row extensions

extension View {
    
    func hideListRowSeparator() -> some View {
        return customListRowSeparator(insets: .init(), insetsColor: .clear)
    }
    
    func customListRowSeparator(
        insets: EdgeInsets,
        insetsColor: Color) -> some View {
        modifier(HideRowSeparatorModifier(insets: insets,
                                          background: insetsColor
        )) .onAppear {
            UITableView.appearance().separatorStyle = .none
            UITableView.appearance().separatorColor = .clear
        }
    }
}

// MARK: ViewModifier

private struct HideRowSeparatorModifier: ViewModifier {
        
    var insets: EdgeInsets
    var background: Color
    
    func body(content: Content) -> some View {
        content
            .padding(insets)
            .frame(
                minWidth: 0,
                maxWidth: .infinity,
                maxHeight: .infinity,
                alignment: .leading
            )
            .listRowInsets(EdgeInsets())
            .background(background)
    }
}

使用:

// Without list row separator
List {
    ForEach(self.viewModel.data, id: \.id) { item in
        Text("Text")
    }
    .hideRowSeparatorItemList()
}

// With list row separator with color and size
List {
    ForEach(self.viewModel.data, id: \.id) { item in
        Text("Text")
    }
    .customListRowSeparator(insets: EdgeInsets(top: 0,
                                               leading: 0,
                                               bottom: 5,
                                               trailing: 0),
                            insetsColor: Color.red)
}

答案 15 :(得分:0)

除了@Mojtaba Hosseini答案外,这是您如何隐藏列表包括最后一个以下的额外分隔符的方法:

init() {
    UITableView.appearance().tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 1))
}

答案 16 :(得分:0)

您可以通过将 listStyle 设置为 InsetListStyle() 来删除分隔符,如下所示:

.listStyle(InsetListStyle())

将此添加到代码的结尾

答案 17 :(得分:0)

  1. 尝试插入.listRowInsets(EdgeInsets(top:5,前导:5,bottom:5,尾随:5))为行添加填充,您可以在VSTack中对其进行样式设置。

     struct ContentView : View {
      var body: some View {
      VStack(alignment: .leading) {
          List(1...10) {_ in
            CustomRow()
       }
        }
        .listRowInsets(EdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5))
      }
      }
    
  2. 第二种方法是:(另外,如果需要传递Binding,则可以在下面看到,如果不忽略enableNext传递的值)。

    struct ContentView : View { 
    @State var enableNextState: Bool = false
         var body: some View {
             VStack(alignment: .leading) {
                  List(1...10) {_ in
                      CustomRow(enableNext: enableNextState )
                      }
                    }
                   }
                }
    
          struct CustomRow: View {
               @Binding var enableNext: Bool
    
                init(enableNext: Binding<Bool>) {
                    self._enableNext = enableNext
                    UITableView.appearance().separatorColor = .clear
    
                  }
    
                  var body: some View {
                    Text("ROW DATA")
                  }
                }
    

答案 18 :(得分:0)

可以只使用负插图和纯色来掩盖分隔符。

答案 19 :(得分:0)

我也有同样的问题。但我知道一个手工制作的解决方案。因此,如果您将 List 行参数设置为:

.listRowInsets(EdgeInsets(top: -5, leading: 0, bottom: 0, trailing: 0))

和行视图主体的填充

.padding(EdgeInsets(top: Statics.adjustValue(v: 10), leading: Statics.adjustValue(v: 10), bottom: Statics.adjustValue(v: 10), trailing: Statics.adjustValue(v: 10)))

然后分隔符将被隐藏。

适用于所有 iOS 版本

答案 20 :(得分:0)

iOS13,iOS14,iOS15,去掉第一个单元格顶部的分隔符

添加视图修饰符

extension View {
    /// 隐藏 List 中的 分割线
    func hideRowSeparator(insets: EdgeInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0),
                          background: Color = .white) -> some View {
        modifier(HideRowSeparatorModifier(insets: insets, background: background))
    }
}

struct HideRowSeparatorModifier: ViewModifier {

  static let defaultListRowHeight: CGFloat = 44

  var insets: EdgeInsets
  var background: Color

  init(insets: EdgeInsets, background: Color) {
    self.insets = insets

    var alpha: CGFloat = 0
    if #available(iOS 14.0, *) {
        UIColor(background).getWhite(nil, alpha: &alpha)
        assert(alpha == 1, "Setting background to a non-opaque color will result in separators remaining visible.")
    }
    self.background = background
  }

  func body(content: Content) -> some View {
    content
        .padding(insets)
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: Self.defaultListRowHeight)
        .listRowInsets(EdgeInsets())
        .overlay(
            VStack {
                HStack {}
                .frame(maxWidth: .infinity)
                .frame(height: 1)
                .background(background)
                Spacer()
                HStack {}
                .frame(maxWidth: .infinity)
                .frame(height: 1)
                .background(background)
            }
            .padding(.top, -1)
        )
  }
}

用法

struct ContentView: View {
    var body: some View {
        List {
            ForEach(0 ..< 30) { item in
                HStack(alignment: .center, spacing: 30) {
                    Text("Hello, world!:\(item)").padding()
                }
                .hideRowSeparator(background: .white)
            }
        }
        .listStyle(PlainListStyle())
    }
}

答案 21 :(得分:0)

对于 iOS 14:

由于 .listRowSeparator(.hidden) 仅适用于 iOS 15,您可以通过将 edgeinsets 显式设置为 0 来隐藏较低版本中的分隔符。

内容视图:

List {
    ForEach(viewModel.items, id: \.id) { item in
        YourListItem(item)
        .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
    }
}

伴随上述变化,将行项的背景设为白色(或根页面的颜色)

行项目:

var body: some View {
    VStack {
        ..... your content
    }
    .background(Colors.white)
}

VStack 只是一个例子。它可以是任何组件。

答案 22 :(得分:-1)

适用于 iOS 13 和 14 的简单解决方案

extension List {
func removeSeparator() -> some View {
    if #available(iOS 14.0, *) {
        return self.listStyle(SidebarListStyle()).erasedToAnyView()
    } else {
        return self.onAppear {
            UITableView.appearance().separatorStyle = .none
        }.erasedToAnyView()
    }
}