首页 > 解决方案 > 服务器回调时按下 SwiftUI 按钮并转到下一个屏幕(下一个视图)

问题描述

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

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

  1. 我需要知道如何初始化/添加活动指示器我在这里找到了一些很酷的示例。我可以将它作为 let 变量存储在我的视图结构中吗?
  2. 然后按按钮取消隐藏/动画指示器
  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 并且想要推送新的视图控制器。

与这个问题非常相似的问题,但我发现它没有用,因为我不知道如何逐步使用如何“创建隐藏的 NavigationLink 并绑定到该状态”

已编辑: 我还发现这个视频答案看起来像是我知道如何进行导航。但是仍然需要弄清楚按下按钮时如何显示活动指示器。

标签: swiftswiftuiswift5

解决方案


要在 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

您可以创建一个类来通过您在项目中放置的 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 文件以在您的代码中使用您的抽签动画:

// 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
    }
  }
}

推荐阅读