Этот код создаст анимацию, которая плавно затухает значения всякий раз, когда я меняю self.myTextString:
// In some View's body method
Text(self.myTextString)
.transition(.opacity)
.animation(.easeInOut(duration: 0.6), value: self.myTextString)
Мне хотелось бы, чтобы старое значение полностью исчезло, а затем начало исчезать в новом значении.
Не казалось ясным/очевидным, как это сделать. Нужно ли мне делать собственный переход? Есть ли где-нибудь примеры, когда кто-то делал такое? (Пусть исходящий что-то сделает и завершится, тогда входящий сможет начать анимацию?)





Я не думаю, что вы можете реализовать это как один переход, вам нужно очистить текст, а затем установить новое значение.
Один из способов сделать это — использовать withAnimation с обратным вызовом completion:
struct ContentView: View {
let part1 = "The quick brown fox"
let part2 = "jumps over the lazy dog"
@State private var myTextString = ""
@State private var showPart1 = true
var body: some View {
VStack {
Text(myTextString)
.animation(.easeInOut(duration: 0.6), value: myTextString)
.frame(height: 50)
Picker("Selection", selection: $showPart1) {
Text(part1).tag(true)
Text(part2).tag(false)
}
.pickerStyle(.segmented)
.fixedSize()
.padding()
.onChange(of: showPart1, initial: true) { oldVal, newVal in
withAnimation {
myTextString = ""
} completion: {
myTextString = newVal ? part1 : part2
}
}
}
}
}

Некоторые примечания:
Переход происходит только тогда, когда одно представление заменяется другим. Если для отображения изменяющегося текста используется одно и то же представление Text (другими словами, меняется только контент), то на самом деле перехода не происходит, а только анимированное изменение. Таким образом, модификатор .transition не требуется.
Вместо модификатора .transition модификатор .contentTransition может оказаться полезным.
В этом примере Text имеет фиксированную высоту, потому что, когда он очищен, он занимает меньше места, чем когда он имеет значение. В противном случае это изменение приводит к тому, что Picker в том же самом VStack немного перемещается.
Если вы знаете задержку, вы можете сделать асимметричный переход и задержать их, чтобы они выглядели так, как вам нравится:
Text(self.myTextString)
.transition(
.asymmetric(
insertion: .opacity.animation(.easeIn.delay(0.6)),
removal: .opacity.animation(.easeOut)
)
)
.id(myTextString)
.animation(.default, value: self.myTextString)

Note transition works for new objects (new identities)
в противном случае вам нужно разбить переход на два отдельных состояния (например, состояние загрузки и состояние завершения) и запустить триггер для каждого отдельно.
Это именно то, что я искал! Я не осознавал, что можно изменить переход с помощью свойства анимации таким образом. Большое спасибо!