91

Let's say I have a SwiftUI view hierarchy that looks like this:

ZStack() {
    ScrollView {
        ...
    }
    Text("Hello.")
}

The Text view blocks touch events from reaching the underlying ScrollView.

With UIKit, I'd use something like .isUserInteractionEnabled to control this, but I can't find any way to do this with SwiftUI.

I've tried adding a Gesture with a GestureMask of .none on the text view, but that doesn't seem to work.

I hope I'm missing something obvious here, because I need to put some status information on top of the scroll view.

LuLuGaGa
  • 13,089
  • 6
  • 49
  • 57
chockenberry
  • 7,811
  • 5
  • 32
  • 41
  • 1
    Between the "rawness" of SwiftUI and the outlier need you described, I'd be surprised if you are missing something obvious - it probably doesn't (yet) exist. –  Sep 11 '19 at 20:40
  • You probably want to put the Text in a frame to make it smaller and contentShape may help too. – Michael Salmon Sep 12 '19 at 08:36
  • @chockenberry It's exactly one year later. Did you find a working solution for the Problem and would you might share it? – Jonas Deichelmann Sep 11 '20 at 12:54
  • Interesting how SwiftUI seemed to automatically disable user interaction if opacity was ≤ 0.5 if I didn't set `allowsHitTesting`. – bjb568 Sep 15 '20 at 01:34
  • This thing is still an issue.. I have a scrollview with a modifier to create a bottom inner shadow, and i can't scroll from where the shadow is... this is ridiculous, anyone has a solution for that? – Oleg G. Sep 25 '20 at 05:39
  • I have the same issue. SwiftUI is a joke. – leonboe1 Oct 21 '20 at 11:25
  • 2
    Found an answer: https://stackoverflow.com/a/61225965/11912101 ```.allowsHitTesting(false)```applying to the ```UIViewControllerWrapper()``` did the trick for me. – leonboe1 Oct 21 '20 at 12:27
  • Probably linked solution actually can helps you! https://stackoverflow.com/a/66313479/6404249 – Daniel Smith Feb 22 '21 at 10:01

9 Answers9

111

What about using the .allowsHitTesting()?

https://developer.apple.com/documentation/swiftui/image/3269586-allowshittesting

From my understanding it should pass the gesture to the view behind if it's disabled.

ZStack() {
    ScrollView {
        ...
    }
    Text("Hello.").allowsHitTesting(false)
}
MihaiL
  • 1,558
  • 1
  • 9
  • 11
  • 2
    It works for me. I have images over background view and want to detect gestures on background. So adding allowsHitTesting(false) on images disables them from interfering with gesture recognitiona and all touches are handled by background view. – Michał Ziobro Apr 22 '20 at 08:16
  • 1
    As a sidenote, this was not working for me initially since I was adding a drop modifier, but when I moved this to be the last modifier it started working. – OwlOCR May 29 '20 at 01:50
  • 1
    This is currently not working for me, I have a Circle in front of a Map UIViewRepresentable and I can't scroll the map if I'm dragging on the Circle itself – Mattia Righetti Jan 17 '21 at 00:56
  • This does not work with iOS14; the Text will block taps where the Text appears in the ZStack. – Jonny Feb 06 '23 at 02:13
  • 1
    omg, Macromedia Flash is back – Dimitar Marinov Jun 19 '23 at 07:46
41

There is a modifier on View to disable or enable user interaction:

disabled(_ disabled: Bool)

LuLuGaGa
  • 13,089
  • 6
  • 49
  • 57
  • I tried putting `.disabled(true)` on both the `Text` and `ZStack` and that didn't help. – chockenberry Sep 11 '19 at 20:51
  • 2
    Apple doc say: "The higher views in a view hierarchy can override the value you set on this view. In the following example, the button isn't interactive because the outer `disabled(_:)` modifier overrides the inner one: HStack { Button(Text("Press")) {} .disabled(false) } .disabled(true) – LuLuGaGa Sep 11 '19 at 21:04
  • Have you tried setting zIndex(1) on one of the views to bring it forward? – LuLuGaGa Sep 11 '19 at 21:19
  • See my own answer above: it appears that the problem isn't the stack or views within it, but rather a problem with .border() doing something unexpected. – chockenberry Sep 11 '19 at 21:31
32

You want to make sure you fill your view with some color, except Clear color (you can always change opacity). I've also added blur to hide elements. Here's what worked for me:

SwiftUI:

ZStack{
    SomeView().blur(radius: 12)
    Rectangle()
        .fill(Color.white.opacity(0))
        .allowsHitTesting(false)
}

Another way to disable user interactions like scroll or button taps, but attach an action to user taps (for example a message to users that this feature is coming or behind a paywall):

SwiftUI:

VStack{
    SomeView().blur(radius: 12)
}
.contentShape(Rectangle())
.onTapGesture {
    print("No access!")
}
Gene Z. Ragan
  • 2,643
  • 2
  • 31
  • 41
Repose
  • 2,157
  • 1
  • 24
  • 26
14

Put your view to be "tap disabled" into a Group then apply the modifier .allowsHitTesting(false) to disable interaction with any view inside the group.

Group {
  Button("Hello")
}
.allowsHitTesting(false)

To enable interaction switch the modifier to true.

zouritre
  • 231
  • 3
  • 6
13

SwiftUI 2.0

 ZStack {

    // Your Stack to Disable User Interaction

}.disabled(showLoadingIndicator)
flyingBear
  • 487
  • 1
  • 6
  • 16
Threadripper
  • 622
  • 10
  • 15
4

This is most likely a bug in SwiftUI, but the workaround for this problem was to remove a .border() that I had put on the Text view for bounds debugging.

chockenberry
  • 7,811
  • 5
  • 32
  • 41
1

Certain elements inside of SwiftUI cannot be disabled through .disabled or .allowHitTesting. A major HACK is to wrap your element in a TabView and apply a paging style to it. Again this is a major hack but it's an interesting solution I'm using currently.

noobular
  • 3,257
  • 2
  • 24
  • 19
0

I'm doing something similar on a watch app, .overlaying a text field over a Slider. I couldn't get either .disable or .allowHitTesting to work when applied to the Text field.

To solve this, I found that placing the Text field in a Group{} (all by itself) and then applying the .allowHitTesting(false) worked perfectly.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
BarryD
  • 41
  • 6
0
ZStack {


}
.allowsHitTesting(false)

it will disabled the user interaction

Neha
  • 666
  • 1
  • 10
  • 17