如何在 SwiftUI 中删除列表中的行分隔符而不使用 ForEach?

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

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

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

请帮帮我,谢谢。

95243 次浏览

IOS15 + :

只需将 .listRowSeparator(.hidden)作为修饰符添加到包含在 List.https://developer.apple.com/documentation/swiftui/texteditor/listrowseparator(_:edges:)中的视图

List {
ForEach(garage.cars) { car in
Text(car.model)
.listRowSeparator(.hidden)
}
}

仅 iOS13:

List出现之前在代码中的任何位置添加 UITableView.appearance().separatorColor = .clear应该可以工作。虽然这个解决方案删除了分隔符,但请注意,所有 List实例都将绑定到这种样式,因为目前还没有官方的方法只删除特定实例的分隔符。您可以在 onAppear中运行这段代码,并在 onDisappear中撤消它,以保持不同的样式。

还要注意,这段代码假设苹果使用 UITableView来支持 List,而在 iOS14SDK 中并非如此。希望将来他们能添加一个官方的 API。归功于 https://twitter.com/singy/status/1169269782400647168

IOS15:

今年苹果推出了一个新的修饰 .listRowSeparator,可以用来风格的分离器。你可以传递 .hidden来隐藏它:

List {
ForEach(items, id:\.self) {
Text("Row \($0)")
.listRowSeparator(.hidden)
}
}

IOS14:

您可以考虑在 ScrollView中使用 LazyVStack(因为 iOS 是 没有,不再支持用于 SwiftUI 列表的 UIAppearance)。

LazyVStack Preview


IOS13:

Something 这种方法已经过时了,在 iOS14上无法工作

在 SwiftUI 的 List后面有一个用于 iOS13的 UITableView

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

你需要一个 tableFooterView和移除

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

你需要 separatorStyle成为 .none

用法示例

init() {
if #available(iOS 14.0, *) {
// iOS 14 doesn't have extra separators below the list by default.
} else {
// 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")
}
}

注意,默认情况下,静态列表不显示额外的分隔符 在名单下面

查看 SwiftUI-内省。它暴露了底层的 UIKit/AppKit视图。

IOS13只能构建:

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

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

比如:

UITableView.appearance().separatorColor = .clear

但在很多情况下,我并不推荐这么做。这些都是全局变更——也就是说,它们将影响 UITableView 的 所有实例。如果您有多个需要不同样式的 UITableView,那么这就是一个问题。或者,如果您正在开发一个框架,那么使用您的框架的客户端也将继承这些更改!

更安全的解决方案是只针对位于指定容器中的 UITableView。幸运的是,appearance api 为我们提供了一种具体的方法:

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

使用 ScrollView? ?

表示列表的某个状态

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

ScrollView中的 SwiftUI ForEach循环

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

IOS13只能构建:

虽然这些答案在技术上是正确的,但从我的经验来看,它们将影响全球(整个应用程序)的 ListForm

我发现解决这个问题的一个古怪的方法,至少在我的应用程序中,是在应用程序的“主”内容视图中添加以下代码:

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

然后,在任何其他视图中,您希望将分隔线添加到 ListForm视图的末尾

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

这似乎将单行分隔符添加到位于主内容视图之上的任何视图表中。这也是我最近在 SwiftUI 上的经历。

根据我的经验,我只需要将 .onAppear(... = .singleLine)方法添加到我的一个“详细”视图中,分隔线就会出现在所有随后呈现的视图中。

编辑: 另一个注释,因为这个答案继续获得关注。我发布的这个解决方案并不能解决所有的问题,它当然也不能解决我的问题,在某些情况下也是如此。我最终使用 SwiftUI 的反思来解决整个应用程序中的这个问题。

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

IOS 14

enter image description here

目前还没有解决方案来隐藏 IOS 14beta 上的分隔符。

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

但是,如果你想留在 List。我发现了一个解决方案在苹果论坛由 Samwarner

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

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

我在 iOS14中启动了一个项目来解决这个问题,因为 iOS13的解决方案不再有效。它允许设置分隔符样式、分隔符颜色和分隔符插入。

隐藏 List 上的分隔符

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

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

但是如果您想使用 List 并且想删除分隔线. 。

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

样本:

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

这是我的扩展 列表 RowExtended,用于 藏起来列表行分隔符和 习俗这个。

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

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

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

然后添加 .padding()为您想要的任何页边距?

拆卸衬垫和分离器

IOS 14.2,Xcode 12.2

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

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

对于 iOS14,你可以这样做:

.listStyle(SidebarListStyle()) # IOS 14

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

.listStyle(InsetListStyle())

将此添加到代码的 结束

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

List() {


}
.listStyle(SidebarListStyle())

一个简单的解决方案,可以在 iOS13和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()
}
}

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

我也有同样的问题。但我知道一个手工解决方案。因此,如果设置 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 版本

对于 iOS13,iOS14并移除第一单元顶部的分隔线

添加视图修饰符

extension View {
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())
}
}

对于 iOS14:

由于 .listRowSeparator(.hidden)只适用于 iOS15,所以可以通过显式地将 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 只是一个例子,它可以是任何组件。

这是我的解决方案,包含了所有的考虑:


let style: UITableViewCell.SeparatorStyle
    

public func body(content: Content) -> some View {
content
.introspectTableView { tableView in
tableView.separatorStyle = .none
}
}
}
 

public extension View {
    

func listSeparator(style: UITableViewCell.SeparatorStyle) -> some View {
ModifiedContent(content: self, modifier: ListSeparatorStyle(style: style))
}
}

执行情况:

List {
// code...
}
.listSeparator(style: .none)

要删除 SwiftUI 中的行分隔符,可以通过附加 onAppear修饰符来调整 List视图,并调用 UITableView的外观 API 来禁用行分隔符:

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

使用这段代码,列表视图的所有行分隔符都应该被删除。

enter image description here

如果只想隐藏底部分隔符,可以这样做

            Text("Hello, world!")
.listRowSeparator(.hidden, edges: [.bottom])