Exploring SwiftUI: HStack and VStack with Zero Spacing
In SwiftUI, VStack
and HStack
components help in arranging views vertically and horizontally. However, their default spacing can vary across different operating systems, catering to each platform's specific needs.
Imagine a scenario where a designer hands you a design with specific spacing requirements for each view. Constantly using VStack(spacing: 0) { }
or HStack(spacing: 0) { }
can quickly become a bit tedious for hundreds of such views.
You can create custom views that provide zero spacing by default, effectively serving as syntactic sugar SwiftUI views. Let's call these custom views ZeroSpacingVStack
and ZeroSpacingHStack
.
We will explore how to create these custom views, along with examples to demonstrate their usage. Time to take control of your view spacing!
ZeroSpacingVStack
This custom view follows a structure similar to SwiftUI's VStack
, allowing you to specify the horizontal alignment and accept a view builder as a parameter:
struct ZeroSpacingVStack<Content>: View where Content: View {
private let viewBuilder: Content
private let horizontalAlignment: HorizontalAlignment
init(_ horizontalAlignment: HorizontalAlignment = .center, @ViewBuilder content: () -> Content) {
self.horizontalAlignment = horizontalAlignment
self.viewBuilder = content()
}
var body: some View {
VStack(alignment: horizontalAlignment, spacing: 0) {
viewBuilder
}
}
To use ZeroSpacingVStack
, simply wrap your views inside it, just like you would with a regular VStack
. By default, the horizontal alignment is set to .center
. Here's an example usage:
ZeroSpacingVStack {
Text(track.title)
.font(.headline)
.padding(.bottom, 8)
Text(track.artistName)
.foregroundColor(.secondary)
.padding(.bottom, 4)
}
In this example, ZeroSpacingVStack
arranges the track title and artist name vertically with zero spacing between them. You can then apply specific .padding()
as required.
If you want to specify a different horizontal alignment, pass it as a parameter to ZeroSpacingVStack
. For instance:
ZeroSpacingVStack(.leading) {
Text(title)
.font(type: .montserrat, weight: .regular, size: 14)
.padding([.leading, .bottom], 4)
Text(subtitle)
.font(type: .montserrat, weight: .light, size: 12)
}
In this case, the views inside ZeroSpacingVStack
will be aligned to the leading edge.
ZeroSpacingHStack
Similar to ZeroSpacingVStack
, the ZeroSpacingHStack
custom view follows the structure of SwiftUI's HStack
. It allows you to specify the vertical alignment and accept a view builder as a parameter:
struct ZeroSpacingHStack<Content>: View where Content: View {
private let viewBuilder: Content
private let verticalAlignment: VerticalAlignment
init(_ verticalAlignment: VerticalAlignment = .center, @ViewBuilder content: () -> Content) {
self.verticalAlignment = verticalAlignment
self.viewBuilder = content()
}
var body: some View {
HStack(alignment: verticalAlignment, spacing: 0) {
viewBuilder
}
}
}
To use ZeroSpacingHStack
, wrap your views inside it, just like you would with a regular HStack
. By default, the vertical alignment is set to .center
. Here's an example usage:
ZeroSpacingHStack {
Text(track.title)
.font(.headline)
.padding([.leading, .bottom], 8)
Spacer()
Text(track.rating)
.foregroundColor(.secondary)
.padding(.trailing, 8)
.padding(.bottom, 4)
}
In this example, ZeroSpacingHStack
arranges the track title and rating horizontally with zero spacing between them. The Spacer()
pushes the rating view to the trailing edge. You can then apply specific .padding()
as required.
To specify a different vertical alignment, pass it as a parameter to ZeroSpacingHStack
. For instance:
ZeroSpacingHStack(.top) {
WebImage(url: track.artwork.url)
.resizable()
.indicator(.activity)
.padding(.leading, 4)
Text(track.title)
.font(type: .montserrat, weight: .bold, size: 14)
}
In this case, the views inside ZeroSpacingHStack
will be aligned to the top.
Conclusion
While these custom views might seem like a lazy approach, they are useful when working on projects with hundreds of views. ZeroSpacingVStack
and ZeroSpacingHStack
provide a consistent way to handle zero spacing across your app.
If you have a better approach or any suggestions to improve these custom views, feel free to reach out to me on Twitter at @rudrankriyam. I am always open to constructive feedback and appreciate any insights you might have.
Thank you for taking the time to read this article. I hope you found it helpful and enjoyable. Happy coding!