I am trying to show Activity indicator view on API call in my swiftUI application. I have created the Activity Indicator view and it's working fine but I want to disable the user interaction while it is being displayed. To achieve this I have also tried allowsHitTesting(false) modifier but of no use :( When I am clicking on the button is clickable.
ContentView
import SwiftUI
struct ContentView: View {
var body: some View {
return NavigationView {
ZStack {
VStack {
Button {
//
print("Button tapped")
} label: {
Text("Tap me")
}
.frame(width: 200, height: 60)
.background(.red)
Spacer()
}
Loading()
.edgesIgnoringSafeArea(.all)
.allowsHitTesting(false)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
IndicatorView
import SwiftUI
struct Loading: View {
var body: some View {
ZStack {
BlurView()
VStack {
Indicator()
}
}.frame(maxWidth: .infinity, maxHeight: .infinity)
.allowsHitTesting(false)
}
}
//struct ActivityIndicatorView_Previews: PreviewProvider {
// static var previews: some View {
// ActivityIndicatorView(show: .constant(true))
// }
//}
struct BlurView: UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<BlurView>) -> UIVisualEffectView {
let effect = UIBlurEffect(style: .systemMaterial)
let view = UIVisualEffectView(effect: effect)
return view
}
func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<BlurView>) {
//
}
}
struct Indicator: UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<Indicator>)-> UIActivityIndicatorView {
let ind = UIActivityIndicatorView(style: .medium)
ind.startAnimating()
return ind
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
//
}
}
CodePudding user response:
You dont need to use .allowsHitTesting(false)
modifier.
Just mark your blur view is not user-interactable. I tested on simulator.
func makeUIView(context: UIViewRepresentableContext<BlurView>) -> UIVisualEffectView {
let effect = UIBlurEffect(style: .systemMaterial)
let view = UIVisualEffectView(effect: effect)
view.isUserInteractionEnabled = false
return view
}
CodePudding user response:
If you want to disable the Button
in your ContentView
, you will have to apply the .allowsHitTesting(_:)
modifier on the button, instead of Loading()
(or BlurView
). It is your button that is checking for taps, after all, not the progress indicator.
struct ContentView: View {
var body: some View {
// ...
Button {
print("Button tapped")
} label: {
Text("Tap me")
}
.frame(width: 200, height: 60)
.background(.red)
.allowsHitTesting(false) // <-- Here
// ...
}
}
Presumably, you want the progress indicator to appear (and the button disabled) only when the API is actually making a call. The 'loading' state of the API would be communicated with some State
variable. I would also suggest using .disabled(_:)
instead of .allowsHitTesting(_:)
, although admittedly they are functionally the same in this scenario.
struct ContentView: View {
@State private var apiIsLoading = false
var body: some View {
// ...
VStack {
Button {
print("Button tapped")
} label: {
Text("Tap me")
}
.frame(width: 200, height: 60)
.background(.red)
.disabled(apiIsLoading) // Button will be disabled when api is in a loading state
Spacer()
}
if apiIsLoading {
Loading()
.edgesIgnoringSafeArea(.all)
}
// ...
}
}