1

I stuck at the pretty simple step when I want to press on the button show loading indicator and if server returns success response then show new view

It's pretty straightforward in UIKit, but with SwiftUI I stuck to do this.

  1. I need to know how to init/add activity indicator I found some cool examples here. Can I just store it as a let variable in my view sruct?
  2. Then by pressing button Unhide/Animate indicator
  3. Make a server request via my rest api service
  4. Wait some time and show new view on success callback or error message.

Nothing super hard, but I stuck here is a button which is a part of my NavigationView. Please help me push to new screen.

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

    })

I found some link but not sure how to use it right.

Not sure I need PresentationButton or NavigationLink at all as I already have a simple Button and want to kind of push new view controller.

Very similar question to this one but I have not find it useful as I don't know how to use step by step how to "Create hidden NavigationLink and bind to that state"

EDITED: I also found this video answer looks like I figure out how to do navigation. But still need to figure out how to show activity indicator when button pressed.

Matrosov Oleksandr
  • 25,505
  • 44
  • 151
  • 277

1 Answers1

5

To show anything you need at some point in SwiftUI, simply use a @State variable. You can use as many of these Bool as needed. You can toggle a new view, animation...

Example

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

As for the animation, I would suggest the use the Lottie framework. You can find some really cool animations:

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

You can find many animations here:

https://lottiefiles.com

And you can create a class to implement your Lottie animation via a JSON file that you dropped in your project:

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) { }
}

Create a SwiftUI file to use your lottie animation in your code:

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

So the final code would look like this with a NavigationLink, and you will have your loader starting at the beginning of your api call, and ending when api call succeeds:

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
    }
  }
}
Roland Lariotte
  • 2,606
  • 1
  • 16
  • 40