51

I'm trying to remove the "row" separators (known as dividers in SwiftUI) from a List in SwiftUI.

I went through the List documentation, but I haven't been able to find a modifier for that.

Any help would be appreciated.

3
  • 1
    Simple rewording to make the post more understandable Commented Jun 7, 2019 at 8:09
  • Kuya's edit makes sense. I'm having the same issue which is how my search engine lead me here. The original author wants to remove the dividing lines that come by default with the List view. Commented Jun 7, 2019 at 17:38
  • @Schiopu Evgheni please mark an answer as accepted and don't let a question be open for years. Thanks Commented Aug 3, 2021 at 5:28

8 Answers 8

32

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 {
    ForEach(items, id:\.self) { 
        Text("Row \($0)")
            .listRowSeparator(.hidden)
    }
}

iOS 14

Apple introduced LazyVStack In iOS 14. you may consider using it instead of list for this:

ScrollView {
    LazyVStack {
        ForEach((1...100), id: \.self) {
           Text("Placeholder \($0)")
        }
    }
}

Keep in mind that LazyVStack is lazy and doesn't render all rows all the time. So they are very performant and suggested by Apple itself in WWDC 2020.


iOS 13

There is a UITableView behind SwiftUI's List for iOS. So to remove

Extra separators (below the list):

you need a tableFooterView and to remove

All separators (including the actual ones):

you need separatorStyle to be .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")
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

I tried your suggestion for iOS 14 with Xcode 12.0 beta 2 (ScrollView / LazyVStack), but it still shows the cell separators. Additionally, List still has the same separators.
Replacing List with Scrollview with VStack messes with the NavigationView with large title
ScrollView { LazyVStack { ForEach((1...100), id: \.self) { Text("Placeholder ($0)") } } } Its nicely done my job on iOS 14
14

iOS 13 builds only

while this solution works correctly let's clean up the work using ViewModifier

public struct ListSeparatorStyleNoneModifier: ViewModifier {
    public func body(content: Content) -> some View {
        content.onAppear {
            UITableView.appearance().separatorStyle = .none
        }.onDisappear {
            UITableView.appearance().separatorStyle = .singleLine
        }
    }
}

now let's make a small extension that would help to hide the details

extension View {
    public func listSeparatorStyleNone() -> some View {
        modifier(ListSeparatorStyleNoneModifier())
    }
}

As you can see, we’ve wrapped our appearance setting code into a neat little view modifier. you can declare it directly now

List {
    Text("1")
    Text("2")
    Text("3")
}.listSeparatorStyleNone()

2 Comments

Great answer, gonna run with this!
This solution doesn't work when you have a 2nd list presented as sheet and you don't want to hide separator in that 2nd list.
10

You may use ForEach within a ScrollView instead of List for dynamic views without any styling

3 Comments

This doesn't work if the ScrollView is inside a VStack
This doesn't lazy display like a list either.
Use a LazyVStack for lazy loading
6

iOS 13 builds only:

The current workaround is to remove them via UIAppearance:

UITableView.appearance(whenContainedInInstancesOf: 
    [UIHostingController<ContentView>.self]
).separatorStyle = .none

Comments

6

iOS 13 builds only:

Adding UITableView.appearance().separatorColor = .clear for initializer

struct SomeView: View {
  init() {
        UITableView.appearance().separatorColor = .clear
    }
}

I hope you to resolve this problem.

Comments

5

iOS 13 builds only:

See existing answers using UITableView.appearance().

⚠️ Be aware that in the iOS 14 SDK, List does not appear to be backed by UITableView. See the alternate solution below:

iOS 14 Xcode 12 Beta 1 only:

I do have a pure SwiftUI solution for iOS 14, but who knows how long it's going to continue working for. It relies on your content being the same size (or larger) than the default list row and having an opaque background.

⚠️ This does not work for iOS 13 builds.

Tested in Xcode 12 beta 1:

yourRowContent
  .padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
  .frame(
    minWidth: 0, maxWidth: .infinity,
    minHeight: 44,
    alignment: .leading
  )
  .listRowInsets(EdgeInsets())
  .background(Color.white)

Or if you're looking for a reusable ViewModifier:

import SwiftUI

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

struct HideRowSeparator_Previews: PreviewProvider {

  static var previews: some View {
    List {
      ForEach(0..<10) { _ in
        Text("Text")
          .hideRowSeparator()
      }
    }
    .previewLayout(.sizeThatFits)
  }
}

7 Comments

This is correct answer for iOS 14. For iOS 13 builds answers with UITableView.appearance().separatorStyle = .none work fine.
It's not removing the separator. It is just adding a .background(Color.white) on a view on top of the separator and blocks the view. try .background(Color.red.opacity(0.2)) to see yourself.
@MojtabaHosseini if you check out the code I posted, you'll see that I'm asserting exactly the same thing! Thanks so much for being so specific about the definition of removing!
this solution still shows the separator on top of the first row in list
This is asinine. Not your code - the NEED for that code. SwiftUI continues to be not ready for prime time. :(
|
5

From: Swiftui Views Mastery Book SwiftUI 2.0 Mark Moeykens

.listStyle(SidebarListStyle()) # IOS 14

You can apply this new list style which will remove the separator lines.

2 Comments

Worked on iOS14 but how to hide > this simbol at the end of row ...
this should be the accepted answer! Also, I was able to just do .listStyle(.sidebar)
1

For iOS13,iOS14,iOS15,and remove the separator at the top of the first cell

Add viewModifier

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

Usage

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

You can find here

https://github.com/wangrui460/HiddenListLine4SwiftUI

iOS / SwiftUI 技术交流

我创建了一个 微信 iOS 技术交流群、SwiftUI 技术交流群,欢迎小伙伴们加入一起交流学习~

可以加我微信我拉你进去(备注iOS),我的微信号 wr1204607318

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.