服务器回调时按下 SwiftUI 按钮并转到下一个屏幕(下一个视图)

Press SwiftUI button and go to the next screen (next view) when server callback

当我想按下按钮显示加载指示器并且如果服务器 returns 成功响应然后显示新视图时,我停留在非常简单的步骤

这在 UIKit 中非常简单,但在 SwiftUI 中我坚持这样做。

  1. 我需要知道如何 init/add activity 指标 我找到了一些很酷的例子 。我可以将它作为 let 变量存储在我的视图结构中吗?
  2. 然后按下按钮 Unhide/Animate 指标
  3. 通过我的 rest api 服务发出服务器请求
  4. 稍等片刻,显示成功回调或错误消息的新视图。

没什么特别难的,但我卡在这里的是一个按钮,它是我的 NavigationView 的一部分。请帮我推送到新屏幕。

    Button(action: {
     // show indicator or animate
     // call rest api service
     // wait for callback and show next view or error alert

    })

我找到了一些 但不确定如何正确使用它。

不确定我是否需要 PresentationButtonNavigationLink,因为我已经有一个简单的 Button 并且想要推送新的视图控制器。

非常相似的问题,但我没有发现它有用,因为我不知道如何逐步使用如何 "Create hidden NavigationLink and bind to that state"

已编辑: 我还发现这个 video answer 看起来我想出了如何进行导航。但仍然需要弄清楚如何在按下按钮时显示 activity 指示器。

要在 SwiftUI 的某个时刻显示您需要的任何内容,只需使用 @State 变量即可。 您可以根据需要使用任意数量的 Bool。您可以切换新视图、动画...

示例:

@State var showNextView = false
@State var showLoadingAnimation = false

Button(action: {
  self.showLoadingAnimation.toggle()
  self.makeApiCall()
}) {
  Text("Show next view on api call success")
}

// Method that handle your api call
func makeApiCall() {
  // Your api call
  if success {
    showLoadingAnimation = false
    showNextView = true
  }
}

关于动画,我建议你使用Lottie框架。您可以找到一些非常酷的动画:

https://github.com/airbnb/lottie-ios

你可以在这里找到很多动画:

https://lottiefiles.com

并且您可以创建一个 class 以通过您在项目中放置的 JSON 文件来实现您的 Lottie 动画:

import SwiftUI
import Lottie

struct LottieRepresentable: UIViewRepresentable {

  let named: String // name of your lottie file
  let loop: Bool

  func makeUIView(context: Context) -> UIView {
    let view = UIView(frame: .zero)

    let animationView = AnimationView()
    let animation = Animation.named(named)
    animationView.animation = animation
    animationView.contentMode = .scaleAspectFit
    if loop { animationView.loopMode = .loop }
    animationView.play()

    animationView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(animationView)

    NSLayoutConstraint.activate([
      animationView.widthAnchor.constraint(equalTo: view.widthAnchor),
      animationView.heightAnchor.constraint(equalTo: view.heightAnchor)
    ])

    return view
  }

  func updateUIView(_ uiView: UIView, context: Context) { }
}

创建一个 SwiftUI 文件以在您的代码中使用您的 lottie 动画:

// MARK: - Show LottieRespresentable as view
struct LottieView: View {

  let named: String
  let loop: Bool
  let size: CGFloat

  var body: some View {
    VStack {
      LottieRepresentable(named: named, loop: loop)
        .frame(width: size, height: size)
    }
  }
}

所以最终代码看起来像这样带有 NavigationLink,并且您的加载程序将在 api 调用开始时开始,并在 api 调用成功时结束:

import SwiftUI

//MARK: - Content view
struct ContentView: View {

  @State var showMessageView = false
  @State var loopAnimation = false

  var body: some View {
    NavigationView {
      ZStack {
        NavigationLink(destination: MessageView(),
                       isActive: $showMessageView) {
          Text("")

          VStack {
            Button(action: {
              self.loopAnimation.toggle()
              self.makeApiCall()
            }) {
              if self.loopAnimation {
                Text("")
              }
              else {
                Text("Submit")
              }
            }
          }

          if self.loopAnimation {
            LottieView(named: "Your lottie json file name",
                       loop: self.loopAnimation,
                       size: 50)
          }
        }
        .navigationBarTitle("Content View")
      }
    }
  }

  func makeApiCall() {
    // your api call
    if success {
      loopAnimation = false
      showMessageView = true
    }
  }
}