1

I want to define a layout like this:

enter image description here

How can I let the Buttons grab all the available width, also when the user resizes the Window.
In the upper part three rows of equal width, in the lower part one row with max. width

struct TEST: View { let columns = [ GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()) ] let data = ["1 Text ...", "2 longer Text ...", "3 Text ...", "4 Text/FA/Tra ...", "5 Text ...", "6 Text ...", "7 Text ...", "8 Text ...", "9 Text ...", ] var body: some View { VStack (alignment: .leading ){ LazyVGrid(columns: columns) { ForEach(data, id: \.self) { item in Button(action: {print("")}){ Text(item).background(Color.green) } .background(Color.yellow) } } .padding(.horizontal) } Button("even longer Text"){print("x")} Button("even longer Text"){print("x")} Button("even longer Text"){print("x")} } } 
1
  • 1
    You can use UIScreen.main.bounds.width/height to get the dimensions of an iPhone. Maybe that works on MacOS, too. Commented Jan 4, 2021 at 17:49

3 Answers 3

1

You can use .frame(maxWidth: .infinity):

Button("even longer Text") { print("x") } .frame(maxWidth: .infinity) 

EDIT

Here is a more detailed example:

var body: some View { VStack(alignment: .leading) { LazyVGrid(columns: columns) { ForEach(data, id: \.self) { item in Button(action: { print("") }) { Text(item) .frame(maxWidth: .infinity) .contentShape(Rectangle()) } .background(Color.yellow) } } .padding(.horizontal) .background(Color.blue) } Button(action: { print("x") }) { Text("even longer Text") .frame(maxWidth: .infinity) .contentShape(Rectangle()) } .background(Color.purple) ... } 

I added colors, so you can see that buttons are aligned properly.

enter image description here

Tested with Xcode 12.3, macOS 11.1

Sign up to request clarification or add additional context in comments.

10 Comments

Doesn't work for me. Anything else to do?
@mica I added a more detailed example with background colors.
Thanks a lot, now the layout works fine - One thing left: it seems, that only the small part of the text inside the Button is clickable, which is not the expected behavior for a Button. Any Idea, how to fix that?
@mica You need to add .contentShape(Rectangle()) - see the updated answer.
.frame(maxWidth: .infinity) doesn't work for me on macOS (11.4) either, a button sticks to its intrinsic size. (works neither within the label, nor outside of the button). Something that works is giving the label a fixed size (via .frame(width: 120), which you could pass in using a GeoReader). I filed FB9335111
|
0

Found a solution:

struct TEST: View { let columns = [ GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()) ] let data = ["1 Text ...", "2 longer Text ...", "3 Text ...", "4 Text/FA/Tra", "5 Text ...", "6 Text ...", "7 Text ...", "8 Text ...", "9 Text ...", ] var body: some View { VStack (alignment: .leading ){ LazyVGrid(columns: columns) { ForEach(data, id: \.self) { item in ExpandingButton(s: item){print("pressed")} } } .padding(.horizontal) } ExpandingButton(s: "Hogo"){print("hogo")} ExpandingButton(s: "Hogo"){print("hogo")} ExpandingButton(s: "Hogo"){print("hogo")} } } struct ExpandingButton: View { var s : String var action: ()->Void var body: some View { HStack (alignment: .top){ Spacer() Text(s) .padding(4) Spacer() } .background(Color.gray) .cornerRadius(4) .onTapGesture {action()} } } 

Comments

0

You can use the frame(maxWidth: .infinity) command. However, the trick is to apply the width style to the label of the button itself as opposed to the actual button declaration.

Here is a sample code on how to do this in Swift UI

Button { doSomething() } label: { Text("Click me").frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) 

source

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.