Removing List’s cell separators in SwiftUI

Currently, as of Xcode 11.1, Apple provides no way for developers to specify a cell separator style for SwiftUI’s List.

Having run into this issue myself, I finally stumbled upon a workaround:

UITableView.appearance().separatorStyle = .none

List seems to respect the UITableView appearance proxy. While this may change in future iOS releases, it’s a good enough solution for the time being.

There is one major caveat - UITableView.appearance() affects the appearance of all Lists in the application. How can we restrict our desired appearance to a single screen?

We utilize a view’s lifecycle events, View.onAppear and View.onDisappear, to set and then unset our custom appearance for a given view.

List {
    Text("a")
    Text("b")
    Text("c")
    Text("d")
}.onAppear {
    UITableView.appearance().separatorStyle = .none
}.onDisappear {
    UITableView.appearance().separatorStyle = .singleLine
}

While this works, it seems rather unwieldly and odd. We can further simplify this code by wrapping part of it in a ViewModifier.

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

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. Our example can now be reduced to:

List {
    Text("a")
    Text("b")
    Text("c")
    Text("d")
}.listSeparatorStyleNone()

Note: There is still one issue that we haven’t solved. While view lifecycle events allow us to set/unset the appearance, they affect all views in a given screen. The subject of our modifier must be destroyed for the appearance to restore to its original state, and thus we cannot prevent it from affecting sibling views. We will tackle this problem in a future post.

 
81
Kudos
 
81
Kudos

Now read this

How to fix Segmentation fault: 11 with @propertyWrapper

I recently encountered a small but annoying bug with property wrappers in Swift 5.1. When building the following code for archiving/profiling: @propertyWrapper public struct Foo<T> { public let wrappedValue: T? public... Continue →