SwiftUI button - only right side tappable

Viewed 53

I have the following SwiftUI view which is essentially a textfield containing a button:

var body: some View {
        ZStack(alignment: .leading) {
            RoundedRectangle(cornerRadius: Constants.cornerRadius, style: .continuous)
                .stroke(isFocused ? Color.blue : hasWarning ? .blue : .gray, lineWidth: Constants.lineWidth)
            
            HStack {
                Text(title)
                    .font(.bodyFont)
                    .foregroundColor(isFocused ? Color.blue : hasWarning ? .red : .gray)
                    .padding(.horizontal, text.isEmpty ? Constants.Padding.horizontalIsEmpty : Constants.Padding.horizontalIsNotEmpty)
                    .background(text.isEmpty ? Color.clear : background)
                    .padding(.leading, Constants.Padding.leading)
                    .offset(y: text.isEmpty ? Constants.Offset.isEmpty : -(frameHeight / Constants.Offset.isNotEmptyRatio))
                    .scaleEffect(text.isEmpty ? Constants.ScaleEffect.isEmpty : Constants.ScaleEffect.isNotEmpty, anchor: .leading)

                if let button = button {
                    Spacer()
                    
                    Button(action: {
                        button.action()
                    }, label: {
                        Text(button.labelText)
                    })
                    .padding(.trailing, Constants.Button.trailingPadding)
                }
            }
            
            TextField("", text: $text, onEditingChanged: { inFocus in
                self.isFocused = inFocus
            })
                .font(.bodyFont)
                .padding(.horizontal, Constants.Padding.horizontal)
        }
        .frame(height: frameHeight)
        .background(background)
        .animation(.easeInOut(duration: Constants.Animation.easeInOut))
        .padding(.top, Constants.Padding.top)
    }

The result is a field like this:

enter image description here

However, only the very right hand side of the button is tappable.

I have tried adding a contentShape, like this:

if let button = button {
                        Spacer()
                        
                        Button(action: {
                            button.action()
                        }, label: {
                            Text(button.labelText)
                        })
                        .contentShape(Rectange())
                        .padding(.trailing, Constants.Button.trailingPadding)
                    }

However this has made no difference. Wondering where I'm going wrong here.

1 Answers

Found the issue! It was a simple mistake.

The HStack including the button needed to be wrapped around this element:

TextField("", text: $text, onEditingChanged: { inFocus in
                self.isFocused = inFocus
            })
                .font(.bodyFont)
                .padding(.horizontal, Constants.Padding.horizontal)

Previously what was happening was that this element was overlapping the button, obscuring the tappable area. So the correct code would be:

        HStack {
            TextField("", text: $text, onEditingChanged: { inFocus in
                self.isFocused = inFocus
            })
                .font(.bodyFont)
                .padding(.horizontal, Constants.Padding.horizontal)
            
            if let button = button {
                
                Spacer()
                
                Button(action: {
                    button.action()
                }, label: {
                    Text(button.labelText)
                })
                    .padding(.trailing, Constants.Button.trailingPadding)
            }
        }
Related