article

Sunday, February 27, 2022

SwiftUI Loading View | Loading Screen

SwiftUI Loading View | Loading Screen

ContentView.swift
 
//
//  ContentView.swift
//  SwiftUIProject
//
//  Created by Cairocoders
//

import SwiftUI

struct ContentView: View {

    @State var progress: CGFloat = 0
    @State var doneLoading: Bool = false
    
    var body: some View {
        ZStack {
            if doneLoading {
                HomeView()
                    .transition(AnyTransition.opacity.animation(.easeInOut(duration: 1.0)))
            } else {
                LoadingView(content: Image("logo")
                                        .resizable()
                                        .scaledToFit()
                                        .padding(.horizontal, 50),
                            progress: $progress)
                    // Added to simulate asynchronous data loading
                    .onAppear {
                        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                            withAnimation {
                                self.progress = 0
                            }
                            DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
                                withAnimation {
                                    self.doneLoading = true
                                }
                                
                            }
                        }
                    }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


struct ScaledMaskModifier<Mask: View>: ViewModifier {
    
    var mask: Mask
    var progress: CGFloat
    
    func body(content: Content) -> some View {
        content
            .mask(GeometryReader(content: { geometry in
                self.mask.frame(width: self.calculateSize(geometry: geometry) * self.progress,
                                height: self.calculateSize(geometry: geometry) * self.progress,
                                alignment: .center)
            }))
    }
    
    // Calculate Max Size of Mask
    func calculateSize(geometry: GeometryProxy) -> CGFloat {
        if geometry.size.width > geometry.size.height {
            return geometry.size.width
        }
        return geometry.size.height
    }

}

struct LoadingView<Content: View>: View {

    var content: Content
    @Binding var progress: CGFloat
    @State var logoOffset: CGFloat = 0 //Animation Y Offset
    
    var body: some View {
        content
            .modifier(ScaledMaskModifier(mask: Circle(), progress: progress))
            .offset(x: 0, y: logoOffset)
            .onAppear {
                withAnimation(Animation.easeInOut(duration: 1)) {
                    self.progress = 1.0
                }
                withAnimation(Animation.easeInOut(duration: 0.4).repeatForever(autoreverses: true)) {
                    self.logoOffset = 10
                }
            }
    }
}
HomeView.swift
 
//
//  HomeView.swift
//  SwiftUIProject
//
//  Created by Cairocoders
//

import SwiftUI

struct HomeView: View {
    var body: some View {
        ZStack {
            Color.blue.ignoresSafeArea()
            VStack {
                Text("Hello, SwiftUI!")
                    .font(.largeTitle)
                    .bold()
                Button("Getting Started") {
                    
                }
            }
        }
        .accentColor(Color.black)
    }
}

struct HomeView_Previews: PreviewProvider {
    static var previews: some View {
        HomeView()
    }
}

Related Post