0

我一直在 SwiftUI 1.0 中开发一个项目,因为它需要支持 iOS 13.0 设备(所以不可fullScreenCover用)。我要求我的应用程序在我的视图之间有干净的过渡动画,所以我在GeometryReader整个应用程序中广泛使用,如下所示:

记录

现在我已经完成了 80% 的 UI,我正在尝试集成数据获取部分。所以,我所做的是onAppear在我的视图上调用我的方法中的数据获取方法。这是我的代码:

struct ContentView: View {

    @State private var isUserLoggedIn = false

    var body: some View {
        GeometryReader { geometry in
            HomeView()
            LoginView(isUserLoggedIn: $isUserLoggedIn)
                .offset(y: isUserLoggedIn ? geometry.size.height + geometry.safeAreaInsets.bottom : 0)
        }
    }
}

struct LoginView: View {

    @Binding var isUserLoggedIn: Bool

    var body: some View {
        Button("Login") {
            withAnimation {
                isUserLoggedIn.toggle()
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.red)
        .edgesIgnoringSafeArea(.all)
        .onAppear {
            print("Login appeared!")
        }
    }
}

struct HomeView: View {

    @State private var isTwoSelected = false

    var body: some View {
        GeometryReader { geometry in
            OneView(isTwoSelected: $isTwoSelected)
                .offset(x: isTwoSelected ? -geometry.size.width : 0)
            TwoView(isTwoSelected: $isTwoSelected)
                .offset(x: isTwoSelected ? 0 : geometry.size.width)
        }
    }
}

struct OneView: View {

    @Binding var isTwoSelected: Bool

    var body: some View {
        NavigationView {
            Button("Goto Two") {
                withAnimation {
                    isTwoSelected.toggle()
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.green)
            .edgesIgnoringSafeArea(.all)
            .navigationBarTitle(Text("One"))
            .onAppear {
                print("One appeared! Fetch data...")
            }
        }
    }
}

struct TwoView: View {

    @Binding var isTwoSelected: Bool

    var body: some View {
        NavigationView {
            Button("Goto One") {
                withAnimation {
                    isTwoSelected.toggle()
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.yellow)
            .edgesIgnoringSafeArea(.all)
            .navigationBarTitle(Text("Two"))
            .onAppear {
                print("Two appeared! Fetch data...")
            }
        }
    }
}

但我现在面临的问题是它们是同时被触发的。可以看到控制台打印如下:

Login appeared!
Two appeared! Fetch data...
One appeared! Fetch data...

仅当它们出现在设备的视图框架中时,我将如何将数据提取到相应的视图?

4

2 回答 2

0

关于获取的问题解决了!看代码,我可以更新动画或其他小东西!它只是为您快速编码。

在此处输入图像描述

import SwiftUI




struct ContentView: View {
    
    @State var isUserLoggedIn: Bool = false
    
    var body: some View {
        
        
        
        Group
        {
            if isUserLoggedIn
            {
                Home()
            }
            else
            {
                LoginView(isUserLoggedIn: $isUserLoggedIn)
            }
        }
        
        
        
    }
}




struct LoginView: View {
    
    @Binding var isUserLoggedIn: Bool
    
    var body: some View {
        
        
        
        Button("Login") { withAnimation(.easeInOut(duration: 1.0)) { isUserLoggedIn.toggle(); print("Successful Login!") } }.font(Font.largeTitle).padding()
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.red)
            .edgesIgnoringSafeArea(.all)
            .offset(y: isUserLoggedIn ? UIScreen.main.bounds.height : 0)
            .onAppear { print("Login appeared!") }
        
        
    }
}

enum appPage {
    case One
    case Two
    case Home
}



struct Home: View {
    
    
    
    @State var currentPage: appPage = appPage.Home
    @State var NavigationViewTitle: String = "Home"
    
    var body: some View {
        
        
        
        
        
        
        
        VStack
        {
            HStack {Text(NavigationViewTitle).font(Font.largeTitle).padding(); Spacer() }.padding()
            
            if      currentPage == appPage.One
            {
                OneView(currentPage: $currentPage, NavigationViewTitle: $NavigationViewTitle)
            }
            else if currentPage == appPage.Two
            {
                TwoView(currentPage: $currentPage, NavigationViewTitle: $NavigationViewTitle)
            }
            else if currentPage == appPage.Home
            {
                
                
                Button(action: {
                    
                    withAnimation { withAnimation(.spring(response: 1, dampingFraction: 0.4, blendDuration: 1)  ) {currentPage = appPage.One} }
                }){
                    HStack {Text("Goto One"); Image(systemName:"arrow.right")}
                }.font(Font.largeTitle).padding()
                
                
                Button(action: {
                    withAnimation { withAnimation(.spring(response: 1, dampingFraction: 0.4, blendDuration: 1)  ) {currentPage = appPage.Two} }
                }){
                    HStack {Text("Goto Two"); Image(systemName:"arrow.right")}
                }.font(Font.largeTitle).padding()
                
                
                
                
            }
            
            
            
            
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.yellow)
        .edgesIgnoringSafeArea(.all)
        .onAppear { print("Home appeared!") }
        .onChange(of: currentPage) { _ in
            
            
            if      currentPage == appPage.One
            {
                NavigationViewTitle = "View One"
            }
            else
            {
                NavigationViewTitle = "View Two"
            }
        }
        
        
    }
}





struct OneView: View {
    
    
    
    @Binding var currentPage: appPage
    @Binding var NavigationViewTitle: String
    
    var body: some View {
        
        
        
        VStack
        {
            
            Button(action: {
                
                withAnimation { withAnimation(.spring(response: 1, dampingFraction: 0.4, blendDuration: 1)  ) {currentPage = appPage.Two} }
            }){
                HStack {Text("Back to Two"); Image(systemName:"arrow.right")}
            }.font(Font.largeTitle).padding()
            
            
            
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.orange)
        .edgesIgnoringSafeArea(.all)
        .cornerRadius(30)
        .offset(x: currentPage == .Two ? UIScreen.main.bounds.width : 0)
        .onAppear { print("OneView appeared! Fetch data...") }
        
    }
}



struct TwoView: View {
    
    
    
    @Binding var currentPage: appPage
    @Binding var NavigationViewTitle: String
    
    var body: some View {
        
        
        
        
        VStack
        {
            
            Button(action: {
                
                withAnimation { withAnimation(.spring(response: 1, dampingFraction: 0.4, blendDuration: 1)  ) {currentPage = appPage.One} }
                
            }){
                HStack {Text("Back to One"); Image(systemName:"arrow.right")}
            }.font(Font.largeTitle).padding()
            
            
            
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.green)
        .edgesIgnoringSafeArea(.all)
        .cornerRadius(30)
        .offset(x: currentPage == .One ? UIScreen.main.bounds.width : 0)
        .onAppear { print("TwoView appeared! Fetch data...") }
        
    }
}
于 2020-11-10T08:08:49.923 回答
0

正如@Asperi 在评论中所说,transition似乎是在此处进行而不是offset. 这是transition(仅添加已更改的视图)的实现:

struct ContentView: View {

    @State private var isUserLoggedIn = false

    var body: some View {
        if isUserLoggedIn {
            HomeView()
                .transition(.asymmetric(insertion: .move(edge: .top), removal: .move(edge: .bottom)))
        } else {
            LoginView(isUserLoggedIn: $isUserLoggedIn)
                .transition(.asymmetric(insertion: .move(edge: .top), removal: .move(edge: .bottom)))
        }
    }
}

struct HomeView: View {

    @State private var isTwoSelected = false

    var body: some View {
        Group {
            if !isTwoSelected {
                OneView(isTwoSelected: $isTwoSelected)
                    .transition(.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .trailing)))
            } else {
                TwoView(isTwoSelected: $isTwoSelected)
                    .transition(.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)))
            }
        }
    }
}
于 2020-11-10T08:58:12.480 回答