Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI can't tap in Spacer of HStack

Tags:

ios

swift

swiftui

I've got a List view and each row of the list contains an HStack with some text view('s) and an image, like so:

HStack{
    Text(group.name)
    Spacer()
    if (groupModel.required) { Text("Required").color(Color.gray) }
    Image("ic_collapse").renderingMode(.template).rotationEffect(Angle(degrees: 90)).foregroundColor(Color.gray)
}.tapAction { self.groupSelected(self.group) }

This seems to work great, except when I tap in the empty section between my text and the image (where the Spacer() is) the tap action is not registered. The tap action will only occur when I tap on the text or on the image.

Has anyone else faced this issue / knows a workaround?

like image 474
Quinn Avatar asked Jul 24 '19 20:07

Quinn


People also ask

Can a VStack have alignment and spacing?

The VStack allows you to stack views vertically, from top to bottom. You can further customize the view by adding alignment or spacing to the VStack.

What is a VStack?

A view that arranges its subviews in a vertical line.


4 Answers

As I've recently learned there is also:

HStack {
  ...
}
.contentShape(Rectangle())
.onTapGesture { ... }

Works well for me.

like image 96
hnh Avatar answered Oct 23 '22 04:10

hnh


Why not just use a Button?

Button(action: { self.groupSelected(self.group) }) {
    HStack {
        Text(group.name)
        Spacer()
        if (groupModel.required) { Text("Required").color(Color.gray) }
        Image("ic_collapse").renderingMode(.template).rotationEffect(Angle(degrees: 90)).foregroundColor(Color.gray)
    }
}.foregroundColor(.primary)

If you don't want the button to apply the accent color to the Text(group.name), you have to set the foregroundColor as I did in my example.

like image 19
rob mayoff Avatar answered Oct 23 '22 05:10

rob mayoff


works like magic on every view:

extension View {
        func onTapGestureForced(count: Int = 1, perform action: @escaping () -> Void) -> some View {
            self
                .contentShape(Rectangle())
                .onTapGesture(count:count, perform:action)
        }
    }
like image 10
Asi Givati Avatar answered Oct 23 '22 03:10

Asi Givati


The best approach in my opinion for accessibility reasons is to wrap the HStack inside of a Button label, and in order to solve the issue with Spacer can't be tap, you can add a .contentShape(Rectangle()) to the HStack.

So based on your code will be:

    Button {
        self.groupSelected(self.group)
    } label: {
        HStack {
            Text(group.name)
            Spacer()
            if (groupModel.required) { Text("Required").color(Color.gray) }
            Image("ic_collapse").renderingMode(.template).rotationEffect(Angle(degrees: 90)).foregroundColor(Color.gray)
        }
        .contentShape(Rectangle())
    }
like image 8
sergioblancoo Avatar answered Oct 23 '22 04:10

sergioblancoo