Suppose I have 3 views in a page-style TabView. I want there to be gaps between the views that are filled with a specific color that’s different than the TabView’s background color.
For example, here are some views with yellow gaps between them:
The gaps should not be visible when the TabView is at rest:
They should only appear when the TabView is being scrolled:
Here’s some sample code:
TabView {
Color.red
.padding(.horizontal, 20)
.background(.yellow)
Color.blue
.padding(.horizontal, 20)
.background(.yellow)
Color.green
.padding(.horizontal, 20)
.background(.yellow)
}
.tabViewStyle(.page(indexDisplayMode: .never))
.indexViewStyle(.page(backgroundDisplayMode: .always))
.frame(width: 150, height: 150)
The padding/background color creates colored gaps, but the gaps are visible when the TabView is at rest:
Is there any way to keep the colored gaps between the views (or have them be drawn by the views), but have the TabView exactly fit the red/blue/green portion of the views?
This effect can be achieved by adding negative horizontal padding to the background behind each view:
TabView {
Color.red
.background {
Color.yellow
.padding(.horizontal, -20)
}
Color.blue
.background {
Color.yellow
.padding(.horizontal, -20)
}
Color.green
.background {
Color.yellow
.padding(.horizontal, -20)
}
}
.tabViewStyle(.page(indexDisplayMode: .never))
.indexViewStyle(.page(backgroundDisplayMode: .always))
.frame(width: 150, height: 150)
.background(.yellow)
However, the yellow stripes do not always disappear as smoothly as shown in the gif above, particularly if the drag gesture only pulls in a smaller fraction of the next view.
A more reliable approach might therefore be to use a ScrollView
with view-aligned .scrollTargetBehavior
. For example:
ScrollView(.horizontal) {
LazyHStack(spacing: 20) {
Color.red
.containerRelativeFrame(.horizontal)
Color.blue
.containerRelativeFrame(.horizontal)
Color.green
.containerRelativeFrame(.horizontal)
}
.scrollTargetLayout()
.background(.yellow)
}
.scrollTargetBehavior(.viewAligned)
.scrollIndicators(.hidden)
.frame(width: 150, height: 150)
.background(.yellow)