#ios #animation #swiftui #tabview #swiftui-geometryeffect
Вопрос:
У меня есть рабочая анимация в представлении SwiftUI, которая прерывается, когда я помещаю это представление в a TabView
, переходим на другую вкладку и возвращаемся. Как я могу это исправить?
Моя точка зрения более сложна, но я свел ее к следующему:
import SwiftUI
@main
struct AnimationTestApp: App {
var body: some Scene {
WindowGroup {
TabView {
ContentView()
.tabItem {
Text("Tab 1")
}
Text("Content 2")
.tabItem {
Text("Tab 2")
}
}
}
}
}
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
@Namespace var namespace
var body: some View {
VStack {
Button(action: {
viewModel.move()
}) {
Text("Move")
}
ZStack() {
Rectangle()
.fill(.gray)
.frame(width: 300, height: 300, alignment: .center)
if viewModel.moved {
RectView()
.matchedGeometryEffect(id: 0, in: namespace, properties: .frame)
.animation(Animation.default.speed(0.5))
.offset(x: 0, y: -130)
} else {
RectView()
.matchedGeometryEffect(id: 0, in: namespace, properties: .frame)
.animation(Animation.default.speed(0.5))
.offset(x: 0, y: 130)
}
}
}
}
}
struct RectView: View {
var body: some View {
Rectangle()
.frame(width: 100, height: 30, alignment: .center)
}
}
final class ViewModel: ObservableObject {
@Published var moved = false
func move() {
moved = !moved
}
}
Вот запись этого кода на экране. При RectView
нажатии анимация плавно перемещается вверх и вниз Move
. После переключения Tab 2
и возврата при первом нажатии Move
он прыгает без анимации. Следующие нажатия снова анимируются.
На самом деле модель представления более сложна. Состояние (в данном случае: moved
) изменяется через некоторое время после нажатия кнопки. Некоторая работа выполняется в фоновом потоке, а затем изменение состояния запускается в основном потоке. Вот почему я не могу перенести анимацию в Button
действие.
Кроме того, вид более сложный. Он RectView
удаляется из глубины иерархии представлений и добавляется где-то совсем в другом месте.
Этот метод func animation(_ animation: Animation?)
устарел в iOS 15. Проблема уже существует в iOS 14 навсегда. Я также попытался удалить animation
модификаторы и поместить moved = !moved
их в withAnimation { }
блок. Все тот же результат.
Как я мог это исправить, сохранив TabView
при этом ?
Комментарии:
1. Пояснение: В моем исходном коде у меня около 40 прямых просмотров (на самом деле они сложнее, чем прямая). Только один или два из них перемещаются при изменении состояния. Они глубоко вложены в иерархию ZStacks, VStacks, GeometryReaders и т. Д. Вот почему мне нужно работать с matchedGeometryEffect и offset.
Ответ №1:
У вас была какая-то плохая проблема с кодированием, вот рабочий код, также вам здесь не нужен matchedGeometryEffect
:
import SwiftUI
@main
struct AnimationTestApp: App {
var body: some Scene {
WindowGroup {
TabView {
ContentView()
.tabItem {
Text("Tab 1")
}
Text("Content 2")
.tabItem {
Text("Tab 2")
}
}
}
}
}
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
VStack {
Button(action: { viewModel.moved.toggle() }) {
Text("Move")
}
ZStack() {
Rectangle()
.fill(Color.gray)
.frame(width: 300, height: 300, alignment: .center)
RectView()
.offset(x: 0, y: viewModel.moved ? -130 : 130)
.animation(Animation.default.speed(0.5), value: viewModel.moved)
}
}
}
}
struct RectView: View {
var body: some View {
Rectangle()
.frame(width: 100, height: 30)
}
}
final class ViewModel: ObservableObject {
@Published var moved: Bool = false
}