Home > Back-end >  Creating a custom VStack Initialiser
Creating a custom VStack Initialiser

Time:01-09

I want to create an initialiser for a VStack that takes my custom enum as it's spacing element. I have this code:

enum Styles {
  enum Spacing: CGFloat {
    case one = 4
    case two = 8
    case three = 16
  }
}

extension VStack where Content: View {
  init(
    alignment: HorizontalAlignment = .center,
    spacing: Styles.Spacing? = nil,
    content: () -> Content
  ) {
    self.init(
      alignment: alignment,
      spacing: spacing?.rawValue ?? Styles.Spacing.three.rawValue,
      content: content
    )
  }
}

When I use my custom VStack initialiser within a @ViewBuilder function, it comes back with the error Type '()' cannot conform to 'View'. Here's an example of when that occurs:

@ViewBuilder
private func textBlock(
  question: String,
  answer: String
) -> some View {
  VStack(
    alignment: .leading,
    spacing: .three
  ) {
    Text(question)
    Text(answer)
  }
}

How can I fix this?

CodePudding user response:

You need to mark your content param as @ViewBuilder:

@ViewBuilder content: () -> Content

Some considerations:

  1. Your current implementation of textBlock doesn't need to be marked as @ViewBuilder (unless you plan to add more views after the VStack), so you can remove that.
  2. The optional spacing parameter will not work at all, because any calls to VStack(alignment: <something>) will collide with your signature (since you provide a default value for spacing) and the compiler will have no clue as to which initializer should be used. So you'll have to make this one non-optional.
  •  Tags:  
  • Related