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