I'm trying to create a custom 'tab' selection control with a horizontal row of options and the user can select one of N number of options. The 'selected' option will have a 'border' around it. Here's a prototype I made:
@objc public enum ContactTabStyle: Int, CaseIterable {
case one, two, three, four
public var segmentTitle: String {
switch self {
case .one: return "Hello"
case .two: return "World"
case .three: return "Three"
case .four: return "Four"
}
}
}
struct SwiftUIView: View {
let segments: [ContactTabStyle] = [.one, .two, .three, .four]
@State var selectedTab: ContactTabStyle = .one
@Namespace var tabName
var body: some View {
HStack {
ForEach(segments, id: \.self) { segment in
Button {
selectedTab = segment
} label: {
Text(segment.segmentTitle)
.padding(12.0)
.border(selectedTab == segment ? Color.blue : Color.clear, width: 3.0)
.cornerRadius(4.0)
.matchedGeometryEffect(id: segment.segmentTitle, in: tabName) // doesn't work
}
}
}
}
}
The view looks and works fine, but I can't get the animation to 'slide' from one selection to another. It just does a normal SwiftUI fade-in-and-out. I believe I should use matchedGeometryEffect to get the sliding effect, but it doesn't seem to be working. I've tried adding the matchedGeometryEffect to the label around the button as well, but it didn't work either.
Here's a preview of what it looks like:

The
Texts don't need to match geometry - it's the borders that need to match geometry.If you use
borderto make a border, the border is not its own "view", so you can't modify only the border withmatchedGeometryEffect. One workaround is to add the border as thebackgroundof either theTextor theButton(these produce slightly different effects - see which you like better).or