I'm creating a scrollable selection bar. I would like a selection indicator under the text to match the width of the text rect above it. So in the image below, the red would fit the full width of the black area.
import SwiftUI
struct TabSelectionView: View {
let tabs: [String]
@State var selectedIndex: Int
var tabHeight: CGFloat = 40
var tabHorizontalPadding: CGFloat = 8
var tabVerticalPadding: CGFloat = 16
var selectedTabColor = Color.primary
var selectedTextColor = Color.white
var unselectedTabColor = Color.gray
var unselectedTextColor = Color.black
var selectionBarColor = Color.red
var selectionBarHeight: CGFloat = 4
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 0) {
ForEach(0..<tabs.count, id: \.self) { index in
tabView(for: index)
}
}
}
}
private func tabView(for index: Int) -> some View {
let isSelected = index == selectedIndex
let tabColor = isSelected ? selectedTabColor : unselectedTabColor
let textColor = isSelected ? selectedTextColor : unselectedTextColor
let barColor = isSelected ? selectionBarColor : unselectedTabColor
return VStack(spacing: 0) {
Text(tabs[index])
.foregroundColor(textColor)
.padding(.horizontal, tabHorizontalPadding)
.padding(.vertical, tabVerticalPadding)
.background(tabColor)
.frame(height: tabHeight - selectionBarHeight)
if selectionBarHeight > 0 {
Rectangle()
.foregroundColor(barColor)
.frame(maxWidth: .infinity)
.frame(height: selectionBarHeight)
}
}
.contentShape(Rectangle())
.onTapGesture {
selectedIndex = index
}
}
}
struct TabSelectionView_Previews: PreviewProvider {
static var previews: some View {
let tabs1 = ["All", "Grouping 1", "Grouping 2", "Grouping 3", "Sub Grouping 1", "Grouping 4", "Groupint 5", "Sub Grouping 2"]
TabSelectionView(tabs: tabs1, selectedIndex: .constant(0))
.previewLayout(PreviewLayout.sizeThatFits)
}
}