#swiftui #swiftui-animation
#swiftui #swiftui-анимация
Вопрос:
Я пытаюсь получить хороший переход для представления, в котором должна отображаться дата. Я даю идентификатор представлению, чтобы SwiftUI знал, что это новая метка, и анимирует ее переходом. Вот сокращенная версия без форматирования и стиля и с большой продолжительностью для лучшей визуализации:
struct ContentView: View {
@State var date = Date()
var body: some View {
VStack {
Text("(date.description)")
.id("DateLabel" date.description)
.transition(.slide)
.animation(.easeInOut(duration: 5))
Button(action: { date.addTimeInterval(24*60*60) }) {
Text("Click")
}
}
}
}
Результат, он работает так, как ожидалось, старая метка анимируется, а новая анимируется:
Но как только я оберну его внутри UIHostingController:
struct ContentView: View {
@State var date = Date()
var body: some View {
AnyHostingView {
VStack {
Text("(date.description)")
.id("DateLabel" date.description)
.transition(.slide)
.animation(.easeInOut(duration: 5))
Button(action: { date.addTimeInterval(24*60*60) }) {
Text("Click")
}
}
}
}
}
struct AnyHostingView<Content: View>: UIViewControllerRepresentable {
typealias UIViewControllerType = UIHostingController<Content>
let content: Content
init(content: () -> Content) {
self.content = content()
}
func makeUIViewController(context: Context) -> UIHostingController<Content> {
let vc = UIHostingController(rootView: content)
return vc
}
func updateUIViewController(_ uiViewController: UIHostingController<Content>, context: Context) {
uiViewController.rootView = content
}
}
В результате новая метка не анимируется, а просто вставляется в конечную позицию, в то время как старая метка анимируется:
У меня более сложный хостинг-контроллер, но это демонстрирует проблему. Я делаю что-то не так с тем, как я обновляю представление контроллера хостинга, или это ошибка в SwiftUI или что-то еще?
Ответ №1:
Состояние не работает должным образом между различными контроллерами хостинга (неясно, является ли это ограничением или ошибкой, просто эмпирическим наблюдением).
Решение заключается в внедрении зависимого состояния внутри представления хостинга. Протестировано с Xcode 12.1 / iOS 14.1.
struct ContentView: View {
var body: some View {
AnyHostingView {
InternalView()
}
}
}
struct InternalView: View {
@State private var date = Date() // keep relative state inside
var body: some View {
VStack {
Text("(date.description)")
.id("DateLabel" date.description)
.transition(.slide)
.animation(.easeInOut(duration: 5))
Button(action: { date.addTimeInterval(24*60*60) }) {
Text("Click")
}
}
}
}
Примечание: вы также можете поэкспериментировать с ObservableObject/ObservedObject
моделью представления на основе — этот шаблон имеет другой жизненный цикл.
Комментарии:
1. Это правильно! Но для меня невозможно сохранить состояние в представлении, поскольку оно поступает извне, не так, как в примере. Я буду играть с ObservableObject tho! Спасибо!