I am currently trying to build some kind of custom segmented control element. My code currently looks like this:
@AppStorage("selectedcountry") private var selectedCountry: Country = .france
@Namespace private var animation
HStack {
ForEach(Country.allCases, id: \.self) { country in
Button {
withAnimation {
selectedCountry = country
}
} label: {
Text(country.flag)
.padding()
}
.frame(maxWidth: .infinity)
.background {
if selectedCountry == country {
RoundedRectangle(cornerRadius: 10)
.fill(Color.accentColor)
.matchedGeometryEffect(id: "country", in: animation)
}
}
}
}
The "RoundedRectangle(cornerRadius: 10)" element is supposed to slide around like in the regular iOS segmented controls. But somehow I just don't get the matched geometry effect to work.
Any advice that you could give me?
Here's how to get it working:
HStack
.HStack {
ForEach(Country.allCases, id: \.self) { country in
Button {
withAnimation {
selectedCountry = country
}
} label: {
Text(country.flag)
.padding()
}
.matchedGeometryEffect(id: country, in: animation, isSource: selectedCountry == country)
.frame(maxWidth: .infinity)
}
}
.background {
RoundedRectangle(cornerRadius: 10)
.fill(Color.accentColor)
.matchedGeometryEffect(id: selectedCountry, in: animation, isSource: false)
}
I couldn't understand why the marker was jumping from one position to another, instead of moving in an animated way. But it's because, the variable that gets updated is @AppStorage
instead of @State
. When you change it to @State
, animations work fine:
@State private var selectedCountry: Country = .france
See SwiftUI: save the state of toggle and keep the animation for some workarounds.