Skip to main content

Struggling to hide the SwiftUI separators in a List or Form? 

 

The challenge

Creating the following form, separation lines appeared between NameLayout, FinalPhoto, RawPhoto, ApertureLayout and SubmitButton.

var body: some View {
    GeometryReader { geometry in
      Form {
        // layout elements
        NameLayout()
        FinalPhoto()
        RawPhoto()
        ApertureLayout()
        SubmitButton()
      }
    }
}

 

What was assessed

separatorStyle = .none

At first I tried adding a style none to remove all separators in the init()

UITableView.appearance().separatorStyle = .none

But no they didn't go away.

 

separatorColor = .clear

Changing the color of the separator to clear in the init()

UITableView.appearance().separatorColor = .clear

But no they didn't go away.

 

ViewModifier - Style

What about if I try a ViewModifier and managing the separator style for the actual element?

struct ListSeparatorStyle: ViewModifier {
  let style: UITableViewCell.SeparatorStyle
  func body(content: Content) -> some View {
    content
      .onAppear() {
        UITableView.appearance().separatorStyle = self.style
      }
  }
}

And to the View extension adding 

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

Finally to the Form add the modifier

Form {
   // ... code ... //
}

.listSeparatorStyle(style: .none)

No - the separator line would not go away!

 

Success - they are gone

ViewModifier row separator

Adding a ViewModifier as in the above example, was a step in the right direction.  However, rather than editing the UITableView, something else was needed to be addressed.

In the ViewModiferExtension.swift file

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

 

Then in the ViewExtension.swift file add

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

 

Now back to the form, all that you need to add is .hideRowSeparator().  Such as:

Form { 
  // layout elements 
  NameLayout()
    .hideRowSeparator()
  FinalPhoto()
    .hideRowSeparator()
  RawPhoto()
    .hideRowSeparator()
  ApertureLayout()
    .hideRowSeparator()
  SubmitButton()
}

Test and check... the separators should now be gone.