У меня есть массив строк, и я пытаюсь анимировать каждую из них как изображение на экране, по одной.
Я делаю что-то, что:
Text, который анимируется (с непрозрачностью и небольшим изменением положения).Я сделал именно это с помощью этого кода:
Group {
let dialogue = [
"string1",
"string2",
"string3",
"string4",
"string5",
"string6"
]
ForEach(0..<dialogue.count, id: \.self) { index in
Text("\(dialogue[index])")
.frame(width: geometryProxy.size.width * 0.25, height: geometryProxy.size.width * 0.25, alignment: .center)
.minimumScaleFactor(0.15)
.multilineTextAlignment(.center)
.foregroundStyle(.white)
.font(.system(size: 25, weight: .medium, design: .serif))
.background(.cyan.opacity(0.5))
.opacity(hasPresentedDialogue ? 1 : 0)
.offset(y: hasPresentedDialogue ? 0 : geometryProxy.size.height * 0.35 - geometryProxy.size.height * 0.375)
.position(x: geometryProxy.size.width * 0.65, y: geometryProxy.size.height * 0.35)
.animation(.easeInOut(duration: 0.75).delay(5 * Double(index)), value: hasPresentedDialogue)
}
.onAppear { withAnimation { hasPresentedDialogue.toggle() } }
}
Ну... почти только это. Я не могу понять, как заставить просмотры исчезнуть до того, как появится следующий. Прямо сейчас они все просто накапливаются друг на друге, что явно не идеально.
Как я могу сделать так, чтобы каждый элемент также исчезал до появления следующего элемента?





У вас неправильная концепция показа диалогов один за другим. Поскольку вы показываете их внутри цикла ForEach, они появятся все сразу.
Я не упомянул ваш индивидуальный дизайн, но поделился концепцией показа каждого текста один раз и перехода к следующему тексту после определенной задержки. Надеюсь, вы сможете сделать вывод и добавить свой собственный дизайн позже.
import SwiftUI
struct ContentView: View {
let dialogue = [
"string1",
"string2",
"string3",
"string4",
"string5",
"string6"
]
let delay = 2 // 2 seconds
@State var currentDialogIndex = 0
var body: some View {
Text(dialogue[currentDialogIndex])
.font(.title)
.onAppear(perform: {
Timer.scheduledTimer(withTimeInterval: TimeInterval(delay), repeats: true) { _ in
withAnimation(.easeInOut(duration: TimeInterval(delay))) {
currentDialogIndex += 1
if currentDialogIndex >= dialogue.count {
currentDialogIndex = 0
}
}
}
})
}
}
Для такого представления в шахматном порядке можно использовать PhaseAnimator:
struct ContentView: View {
let dialogue = [
"string1",
"string2",
"string3",
"string4",
"string5",
"string6"
]
@State private var hasPresentedDialogue = false
var body: some View {
GeometryReader { geometryProxy in
let w = geometryProxy.size.width
let h = geometryProxy.size.height
PhaseAnimator(dialogue, trigger: hasPresentedDialogue) { string in
Group { // needed for transitions to work
Text(string)
.frame(width: w * 0.25, height: w * 0.25)
.minimumScaleFactor(0.15)
.multilineTextAlignment(.center)
.foregroundStyle(.white)
.font(.system(size: 25, weight: .medium, design: .serif))
.background(.cyan.opacity(0.5))
.id(string) // needed for transitions to work
.transition(
.asymmetric(
insertion: .push(from: .top),
removal: .opacity
)
)
}
} animation: { _ in
.easeInOut(duration: 0.75).delay(1) // delay(5)
}
.padding(.leading, w * 0.525)
.padding(.top, (h * 0.35) - (w * 0.125))
.onAppear { hasPresentedDialogue.toggle() }
}
}
}

Если вы попробуете приведенный выше код, вы обнаружите, что он не запускается и не останавливается так аккуратно, как на гифке. Это потому, что PhaseAnimator работает по-своему:
Чтобы исправить это при записи gif, я использовал пустую строку в начале массива. Внутри замыкания я использовал оператор if для проверки пустой строки:
Group {
if !string.isEmpty {
// content as before
}
}
Таким образом, первая фаза может быть полностью подавлена. Если вы решите использовать тот же подход, возможно, вам захочется подавить и задержку, связанную с анимацией (только для первой фазы).
Другие способы решения проблемы «возврата к началу» можно найти в ответах на сообщение Как использовать PhaseAnimator для создания анимации, которая не возвращается к первой фазе?.
Это тоже отличный вариант, я его рассмотрю. Спасибо.
Спасибо. Я заставил его работать, но не могу понять, как заставить каждый из них двигаться вниз в качестве смещения. Только первый движется вниз.