'How to remove List Separator lines in SwiftUI 2.0 in iOS 14 and above

So the question is pretty simple and it's in the title. I want to remove the line separator in SwiftUI iOS 14. Previously, I was using UITableView().appearance().separatorStyle = .none and that used to do the job in iOS 13. Now however, it doesn't work. Any update or idea on how to make it work. Thanks:)



Solution 1:[1]

Here is a demo of possible solution. Tested with Xcode 12b.

demo

List {
    ForEach(0..<3) { _ in
        VStack {
            Text("Hello, World!").padding(.leading)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
        .listRowInsets(EdgeInsets())
        .background(Color(UIColor.systemBackground)))
    }
}

backup

Solution 2:[2]

How I made a list that works on both iOS 14 and iOS 13, It shows no separators and extra margins

struct NoButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
    }
}

struct ListWithoutSepatorsAndMargins<Content: View>: View {
        let content: () -> Content
    
        var body: some View {
            if #available(iOS 14.0, *) {
                ScrollView {
                    LazyVStack(spacing: 0) {
                        self.content()
                    }
                    .buttonStyle(NoButtonStyle())
                }
            } else {
                List {
                    self.content()
                }
                .listStyle(PlainListStyle())
                .buttonStyle(NoButtonStyle())
            }
        }
    }

Sample Usage -

ListWithoutSepatorsAndMargins {
    ForEach(0..<5) { _ in
      Text("Content")
    }
}

in case you've more components in list, wrap them in Group

                ListWithoutSepatorsAndMargins {
                    Group {
                            self.groupSearchResults()
                            self.myGroups()
                            self.exploreGroups()
                        }
                    }
                }

    

Hope this helps someone, I wasted a lot of time in such minor thing, Apple is trying to push us hard to use LazyVStack, it seems

Solution 3:[3]

Merged @asperi, @akmin and @zrfrank answer into one thing. In my experience List is more reliable and efficient than LazyVStack, so I use still use List for anything complex requiring reliability.

extension View {
    func listRow() -> some View {
        self.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
            .listRowInsets(EdgeInsets(top: -1, leading: -1, bottom: -1, trailing: -1))
            .background(Color(.systemBackground))
    }
}

List {
    Color.red
         .listRow()


    Color.green
         .listRow()
}

Solution 4:[4]

I found this simple solution on the Apple Developer forums. It's working for me on 14.4:

List {
   ...
}.listStyle(SidebarListStyle())

This seems to add a tiny bit of padding around the edges. If that's a problem for you, you could try some negative padding.

Solution 5:[5]

iOS 15:

This year Apple introduced a new modifier .listRowSeparator that can be used to style the separators. you can pass .hidden to hide it:

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

? Also you can set each separator to any color by settings listRowSeparatorTintColor as I mentioned here in this answer:

Demo

iOS 14

Follow the answer here

Solution 6:[6]

Based on average Joe's answer I ended up with the following modifier:

struct ListSeparatorNone: ViewModifier {

    var backgroundColor: Color = Color(.systemBackground)
    
    func body(content: Content) -> some View {
        content
            .listRowInsets(EdgeInsets(top: -1, leading: 0, bottom: 0, trailing: 0))
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
            .background(backgroundColor)
    }
}

The view extension:

extension View {
    func listSeparatorNone(backgroundColor: Color = Color(.systemBackground)) -> some View {
        self.modifier(ListSeparatorNone(backgroundColor: backgroundColor))
    }
}

Usage example:

List {
    ForEach(viewModel.countries, id: \.self) { country in
        Text(country)
            .padding(.leading, 10)
    }
    .listSeparatorNone()
}

Solution 7:[7]

If you don't have a lot of cells, and therefore don't need to rely on a LazyVStack for performance, you can fallback to a ScrollView + VStack:

ScrollView {
  VStack {
    Row1()
    Row2()
    Row3()
  }
}

Solution 8:[8]

You can also call this function at the end of your VStack (that is inner the List).

It will be an overlay on List Seperator on iOS 14 :)

private func hideDefaultListSeperator() -> some View {
    Rectangle()
        .fill(colorScheme == .light ? Color.white : Color.black)
        .frame(maxHeight: 1)
}

Solution 9:[9]

Update:

I figured out a solution that works on both iOS 13 and iOS 14 and gives a simple list and uses List on both iOS.

struct ListWithoutSepatorsAndMargins<Content>: View where Content: View {
    let content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        List {
            self.content()
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
                .listRowInsets(EdgeInsets())
                .background(Color.white)
        }
        .listStyle(PlainListStyle())
        .buttonStyle(NoButtonStyle())
    }
}

struct NoButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
    }

and do the following in SceneDelegate.swift to remove default grey selection of cells

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    UITableView.appearance().separatorStyle = .none
    UITableView.appearance().allowsSelection = false
   .......

and we can use it the following way

ListWithoutSepatorsAndMargins {
    ForEach(0..<5) { _ in
      Text("Content")
    }
}

ListWithoutSepatorsAndMargins {
     Group {
        self.groupSearchResults()
        self.myGroups()
        self.exploreGroups()
     }
  }
}

Solution 10:[10]

Here is my solution for iOS 14:

struct MyRowView: View {
  var body: some View {
    ZStack(alignment: .leading) {
      // Background color of the Row. It will spread under the entire row.
      Color(.systemBackground)
      NavigationLink(destination: Text("Details")) {
        EmptyView()
      }
      .opacity(0) // Hide the Disclosure Indicator

      Text("Go to Details").padding(.leading)
    }
    // These 2 lines hide the row separators
    .padding(.horizontal, -16) // Removes default horizontal padding
    .padding(.vertical, -6)    // Removes default vertical padding
  }
}

The enclosing List should have this modifier

.listStyle(PlainListStyle())

The upside of this solution over using a LazyVStack is that you can still use the Edit capabilities of the List.

This solution relies unfortunately on hard-coded values to remove the system default paddings on each row. Hopefully SwiftUI 3.0 will provide simple .separatorStyle(.none) and .accessoryType(.none) modifiers.

The code to remove the Disclosure Indicators comes from: https://www.appcoda.com/hide-disclosure-indicator-swiftui-list/

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 average Joe
Solution 4 Mark Phillips
Solution 5
Solution 6 Tzegenos
Solution 7 Senseful
Solution 8 Ehsan Askari
Solution 9 Harish saini
Solution 10