ios – Reusing a costly view in SwiftUI

0
20
ios – Reusing a costly view in SwiftUI


I’ve a costly GIF animated view that I take advantage of as a exercise indicator and it must be utilized in lots of locations within the UI, wherever the consumer encounters a API name.

Within the UIKit world, I’d heat up a UIView with the animated gif, and create a brand new UIWindow, hold a reference to it and add it as a root view and make the window seen and hidden when required. Straightforward.

Nonetheless I’ve a tough time determining how I might obtain the identical in SwiftUI. Or possibly I am going about this all unsuitable. Assist appreciated!

Not that it’d assist, however what I had in thoughts for the loading indicator, which I’d name by way of .modifier(LoadingIndicator(...)) wherever required.

struct LoadingIndicator: ViewModifier {
    var isShowing: Bool
    @ViewBuilder
    var progressView: () -> ProgressViewType
    func physique(content material: Content material) -> some View {
        ZStack {
            content material
            if isShowing {
                loadingView
            }
        }
    }
    
    personal var loadingView: some View {
        GeometryReader { proxyReader in
            ZStack {
                Shade.white.opacity(0.1)
                    .body(maxWidth: .infinity, maxHeight: .infinity)
                
                progressView()
            }
        }
        .ignoresSafeArea()
        //.transition(AnyTransition.opacity.animation(.easeInOut(length: 0.2)))
    }
}

Edit:

Okay, that is what I’ve to this point. To make clear the costly bit, the loading indicator that’s getting used is a GIF. I ran and profiled my app a few instances and the reminiscence utilization shoots up.

Each time I profiled when the loading indicator is displayed, the CPU utilization reads 20% for a second, whereas hovering round 2% in any other case. I am no a specialist, however would not steadily allocating and deallocating drain battery life?

If it is a non-issue, I’m comfortable to go away it as is, since this works as anticipated.

I’ve trimmed down and added a reproducible instance:

This requires the SDWebImageSwiftUI package deal. And any 10MB GIF.

import Basis
import SwiftUI
import SDWebImageSwiftUI

extension View {
    
    @ViewBuilder
    func `if`(_ situation: Bool, rework: (Self) -> some View) -> some View {
        if situation {
            rework(self)
        } else {
            self
        }
    }
}

struct LoadingIndicator: ViewModifier {
    var isShowing: Bool
    @ViewBuilder
    var progressView: () -> ProgressViewType
    func physique(content material: Content material) -> some View {
        ZStack {
            content material
            if isShowing {
                loadingView
            }
        }
    }
    
    personal var loadingView: some View {
        GeometryReader { proxyReader in
            ZStack {
                Shade.white.opacity(0.1)
                    .body(maxWidth: .infinity, maxHeight: .infinity)
                
                progressView()
            }
        }
        .ignoresSafeArea()
        .transition(AnyTransition.opacity.animation(.easeInOut(length: 0.2)))
    }
    
    fileprivate static var defaultProgressView: some View {
        ProgressView()
            .progressViewStyle(
                CircularProgressViewStyle(tint: .white)
            )
            .scaleEffect(x: 2, y: 2, anchor: .heart)
            .background(
                RoundedRectangle(cornerRadius: 16)
                    .foregroundColor(Shade.black.opacity(0.7))
                    .body(width: 80, peak: 80)
            )
    }
}

extension View {
    func loadingIndicator(_ isShowing: Bool, @ViewBuilder progressView: @escaping () -> ProgressView) -> some View {
        
        self.if(isShowing) { $0.blur(radius: 10) }
            .modifier(LoadingIndicator(isShowing: isShowing, progressView: progressView))
    }
    
    func tpActivityIndicator(_ isShowing: Bool) -> some View {
        
        loadingIndicator(isShowing) {
            VStack {
                AnimatedImage(identify: "loading_indicator.gif")
                    .resizable()
                    .scaledToFit()
                    .body(width: 130, peak: 150)
                Textual content("Loading...")
                    .font(.physique)
                    .foregroundStyle(Shade.white)
            }
        }
    }
}

#Preview {
    VStack {
        Textual content("Lorem Ipsum")
    }
    .padding()
    .background { Shade.yellow }
    .clipShape(RoundedRectangle(cornerRadius: 5))
    .tpActivityIndicator(true)
}

LEAVE A REPLY

Please enter your comment!
Please enter your name here