Как добавить анимацию в транзитоны между пользовательскими элементами навигации, созданными из AnyView?
Есть ли способ добавить анимацию к переходам между пользовательскими NavigationItem
s сделан из AnyView
как описано в этой статье?
Мне все в этом нравится NavigationStack
системе, за исключением того, что нельзя добавлять анимированные переходы.
Я так понимаю, проблема связана с стиранием текста some View
s с AnyView
, как описано в этом ответе, и чтоGroup
кажется лучшим выбором для анимации пользовательской навигации по представлениям.
Вместо того, чтобы использовать AnyView и стирание типов, я предпочитаю инкапсулировать условную логику внутри группового представления. Затем возвращаемый тип - Group, который будет правильно анимирован.
У меня закончились идеи, и мне нужна помощь.
Я добавлю свой код для контекста.
SceneDelegate:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
...
let contentView = ContentView().environmentObject(UserData())
...
}
ContentView:
struct ContentView: View {
@EnvironmentObject var userData: UserData
var body: some View {
NavigationHost()
.environmentObject(NavigationStack(
NavigationItem(view: AnyView(
(userData.isSignedIn ? AnyView(HomeView()) : AnyView(RegisterView1(profile: Profile.default)) )
.transition(.move(edge: .trailing))
.animation(Animation.linear(duration: 1))))))
//this animation works for some reason, but only this one.
.environmentObject(UserData())
}
}
NavigationHost:
struct NavigationHost: View{
@EnvironmentObject var navigation: NavigationStack
@EnvironmentObject var userData: UserData
var body: some View {
ZStack {
self.navigation.currentView.view
.environmentObject(self.userData)
.environmentObject(self.navigation)
...
}
}
}
}
NavigationStack:
final class NavigationStack: ObservableObject {
@Published var viewStack: [NavigationItem] = []
@Published var currentView: NavigationItem
init(_ currentView: NavigationItem ){
print("Navigation Stack Initialized")
self.currentView = currentView
}
func back() {
if viewStack.count == 0 {
return
}
let last = viewStack.count - 1
currentView = viewStack[last]
viewStack.remove(at: last)
}
navigation.advance(NavigationItem(AnyView))
func advance(_ view: NavigationItem) {
viewStack.append( currentView )
currentView = view
}
func home() {
currentView = NavigationItem( view: AnyView(HomeView()) )
viewStack.removeAll()
}
}
struct NavigationItem{
var view: AnyView
}
1 ответ
Вот обновленные сущности из этой статьи, которые используют простые анимированные переходы между экранами. Все это неуклюже и только для демонстрации, но надеюсь, что это может быть как-то полезно.
Примечание: переходы не работают в предварительном просмотре (по крайней мере, в моем Xcode 11.2/iOS 13.2), поэтому протестированы в симуляторе или реальном устройстве.
Вот как это выглядит:
Вот код:
final class NavigationStack: ObservableObject {
enum Direction {
case root
case forward
case backward
}
@Published var viewStack: [NavigationItem] = []
@Published var currentView: NavigationItem
@Published var navigate: Direction = .root
init(_ currentView: NavigationItem ){
self.currentView = currentView
}
func unwind(){
if viewStack.count == 0{
return
}
let last = viewStack.count - 1
currentView = viewStack[last]
withAnimation {
self.navigate = .backward
}
viewStack.remove(at: last)
}
func advance(_ view:NavigationItem){
viewStack.append( currentView)
currentView = view
withAnimation {
self.navigate = .forward
}
}
func home( ){
currentView = NavigationItem(view: AnyView(HomeView()))
viewStack.removeAll()
withAnimation {
self.navigate = .root
}
}
}
struct NavigationHost: View{
@EnvironmentObject var navigation: NavigationStack
var body: some View {
ZStack(alignment: .topLeading) {
if navigation.navigate == .root {
self.navigation.currentView.view
}
else if navigation.navigate == .backward {
self.navigation.currentView.view
.transition(.move(edge: .leading))
}
if navigation.navigate == .forward {
self.navigation.currentView.view
.transition(.move(edge: .trailing))
}
}
}
}