Button behaviour changes if position(x:y)

With this code, button is at the center of the view and message is logged only when tapping in the button

1. struct ContentView: View {
2.     var body: some View {
3.         
4.         ZStack {
5.             Button(action: {
6.                 print("Touched")    
7.             }) {
8.                 Image(systemName: "square.split.diagonal.2x2")
9.                     .font(.system(size: 24))
10.                     .foregroundColor(.black)
11. //                    .position(x: 12, y: 12)
12.             }
13.             
14.         }
15.         .frame(width: 300, height: 300)
16.         .background(Color.yellow)
17.     }
18. }

But if I uncomment line 11, the message is logged on tap anywhere in the view.

How is it position() changes the behaviour ?

Answered by Claude31 in 740938022

I finally found a solution. Enclose Button in a HStack and apply position modifier to HStack and not directly to image.

struct ContentView: View {
    var body: some View {
        
        ZStack {
            HStack {  // <<-- ENCLOSE IN HStack
                Button(action: {
                    print("Touched")    
                }) {
                    Image(systemName: "square.split.diagonal.2x2")
                        .font(.system(size: 24))
                        .foregroundColor(.black)
                     //   .position(x: 12, y: 12)  // <<-- NOT HERE 
                }
                
            }
            .position(x: 12, y: 12) // <<-- MOVED HERE
        }
        .frame(width: 300, height: 300)
        .background(Color.yellow)
    }
}

What is the reason why ?

It is just as if position(x:y:) was messing up with frame.

I tried this:

  • frame after position
                Image(systemName: "square.split.diagonal.2x2")
                    .font(.system(size: 24))
                    .foregroundColor(.black)
                    .position(x: 12, y: 12)
                    .frame(width: 24, height: 24)

Tap works correctly (only in the button, with a small padding around), but button is no more in its topleft position

  • Whilst with position after frame:
                Image(systemName: "square.split.diagonal.2x2")
                    .font(.system(size: 24))
                    .foregroundColor(.black)
                    .frame(width: 24, height: 24)
                    .position(x: 12, y: 12)

Button is well positioned,

but tap reacts on the whole yellow view

Instead of using position(), I tried to offset the button:

                Image(systemName: "square.split.diagonal.2x2")
                    .font(.system(size: 24))
                    .foregroundColor(.black)
                    .frame(width: 24, height: 24)
                    // .position(x: 12, y: 12)
                    .offset(x:-140, y:-140)

The button moves at the top left, but tap works only at the original position (at the center)

Accepted Answer

I finally found a solution. Enclose Button in a HStack and apply position modifier to HStack and not directly to image.

struct ContentView: View {
    var body: some View {
        
        ZStack {
            HStack {  // <<-- ENCLOSE IN HStack
                Button(action: {
                    print("Touched")    
                }) {
                    Image(systemName: "square.split.diagonal.2x2")
                        .font(.system(size: 24))
                        .foregroundColor(.black)
                     //   .position(x: 12, y: 12)  // <<-- NOT HERE 
                }
                
            }
            .position(x: 12, y: 12) // <<-- MOVED HERE
        }
        .frame(width: 300, height: 300)
        .background(Color.yellow)
    }
}

What is the reason why ?

Button behaviour changes if position(x:y)
 
 
Q