如何将动画添加到由 AnyView 制作的自定义导航项之间的过渡?
How do I add Animations to Transitons between custom NavigationItems made from AnyView?
有没有办法将动画添加到自定义 NavigationItem
之间的过渡,如 this article 中所述,由 AnyView
制作?
我喜欢这个 NavigationStack
系统的一切,除了无法添加任何动画过渡。
我知道问题与 AnyView
类型擦除 some View
有关,如 中所述,并且 Group
似乎更好动画自定义视图导航的选择。
Rather that using AnyView and type-erasure, I prefer to encapsulate the conditional logic inside of a Group view. Then the type you return is Group, which will animate properly.
我 运行 没有想法,我需要一些帮助。
我会为上下文添加我的代码。
场景代理:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
...
let contentView = ContentView().environmentObject(UserData())
...
}
内容视图:
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())
}
}
导航主机:
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)
...
}
}
}
}
导航堆栈:
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
}
此处更新了该文章中的实体,以在屏幕之间采用简单的动画转换。所有这些都是粗糙的,仅用于演示,但希望它能以某种方式提供帮助。
注意:过渡在预览版中不起作用(至少在我的 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))
}
}
}
}
有没有办法将动画添加到自定义 NavigationItem
之间的过渡,如 this article 中所述,由 AnyView
制作?
我喜欢这个 NavigationStack
系统的一切,除了无法添加任何动画过渡。
我知道问题与 AnyView
类型擦除 some View
有关,如 Group
似乎更好动画自定义视图导航的选择。
Rather that using AnyView and type-erasure, I prefer to encapsulate the conditional logic inside of a Group view. Then the type you return is Group, which will animate properly.
我 运行 没有想法,我需要一些帮助。
我会为上下文添加我的代码。
场景代理:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
...
let contentView = ContentView().environmentObject(UserData())
...
}
内容视图:
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())
}
}
导航主机:
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)
...
}
}
}
}
导航堆栈:
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
}
此处更新了该文章中的实体,以在屏幕之间采用简单的动画转换。所有这些都是粗糙的,仅用于演示,但希望它能以某种方式提供帮助。
注意:过渡在预览版中不起作用(至少在我的 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))
}
}
}
}