It's hard to describe my problem in words.
I want to do a selector behave like that.
But after I change the browse direction, because I already set the in and out transition, even if I change the transition to the new one, the view still uses the old one to disappear. (the first one and the last one)
Is there some way to solve the problem?
Here is the code
@State var translations:[String] = ["未知"]
@State var index = 0
@State var transition:AnyTransition = .asymmetric(insertion: .move(edge: .trailing), removal:.move(edge: .leading)).combined(with: .opacity)
var transTexts:some View{
HStack{
if(translations.count > 1){
Button {
if(index > 0){
transition = .asymmetric(insertion: .move(edge: .leading), removal:.move(edge: .trailing)).combined(with: .opacity)
disabled.toggle()
index -= 1
}
} label: {
Image(systemName:"arrowtriangle.backward.circle.fill")
}
.disabled(index == 0)
Text(translations[index])
.scroll()
.font(.body)
.id(index)
.disabled(disabled)
.transition(transition)
}
Spacer()
if(translations.count > 1){
Button {
if(index < translations.count-1){
transition = .asymmetric(insertion: .move(edge: .trailing), removal:.move(edge: .leading)).combined(with: .opacity)
disabled.toggle()
index += 1
}
} label: {
Image(systemName:"arrowtriangle.forward.circle.fill")
}
.disabled(index == translations.count - 1)
}
}
.animation(.default,value: index)
I tried manually controlling which transition it is, by using a Toggle
. The transition works correctly if I just toggled the toggle before I switched direction. e.g. go right 3 times, toggle, then go left 3 times.
When you do this automatically with buttons, it seems like the time when index
changes is "too close" to when transition
changes, and doesn't have the same effect as when I do it manually.
If you just delay the change of index
by a tiny amount of time, it should work.
transition = ...
DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
index += 1 // or -= 1
}
Interestingly, DispatchQueue.main.async { ... }
doesn't work. You have to give it some time.
I'd also suggest using a Bool
or enum to encode the direction it is going in, rather than an AnyTransition
.
Working code:
@State var translations:[String] = ["Lorem Ipsum", "Foo Bar baz", "Something Else", "AAAAA", "BBBBB"]
@State var index = 0
@State var isForward = true
var body:some View{
VStack {
HStack{
if(translations.count > 1){
Button {
if(index > 0){
isForward = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
index -= 1
}
}
} label: {
Image(systemName:"arrowtriangle.backward.circle.fill")
}
.disabled(index == 0)
}
if translations.count > 0 {
Text(translations[index])
.font(.body)
.id(index)
.transition(
// I did not combine with .opacity here to make it more obvious
isForward ?
.asymmetric(insertion: .move(edge: .trailing), removal:.move(edge: .leading)) :
.asymmetric(insertion: .move(edge: .leading), removal:.move(edge: .trailing))
)
}
Spacer()
if(translations.count > 1){
Button {
if index < translations.count - 1 {
isForward = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
index += 1
}
}
} label: {
Image(systemName:"arrowtriangle.forward.circle.fill")
}
.disabled(index == translations.count - 1)
}
}
.animation(.default,value: index)
}
}