我一直在使用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...
仅当数据出现在设备的视图框中时,我该如何将其提取到相应的视图?
答案 0 :(得分: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...") }
}
}
答案 1 :(得分: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)))
}
}
}
}