Argas
Argas

Reputation: 1527

How to make width of view equal to superview in SwiftUI

I have Button

enter image description here

struct ContentView : View {
    var body: some View {
        HStack {
            Button(action: {}) {
                Text("MyButton")
                    .color(.white)
                    .font(Font.system(size: 17))
            }
            .frame(height: 56)
            .background(Color.red, cornerRadius: 0)
        }
    }
}

But I want to pin it to supreview's edges (trailing to superview's trailing and leading). Like this:

enter image description here

HStack doesn't help me, and it's expecting. Fixed frame or width equals UIScree.size are not flexible solutions.

Upvotes: 60

Views: 55769

Answers (6)

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119178

πŸ’‘iOS 17

From iOS 17, the correct way to do this is to use .containerRelativeFrame modifier because using .infinity width on the frame actually pushes the parent's frame to have an infinite width.

So it would be like:

Button(action: {}) {
    Text("MyButton")
        .foregroundStyle(.white)
        .containerRelativeFrame(.horizontal) // πŸ‘ˆ This should be inside the `label` parameter of the `button`. Otherwise it would be NOT touchable
        .padding(-10) // πŸ‘ˆ This is here to make space to the edges. Yes it should have a NEGATIVE value
}
.frame(height: 56)
.background(.red)

Upvotes: 6

DenFav
DenFav

Reputation: 2811

You need to use .frame(minWidth: 0, maxWidth: .infinity) modifier

Add the next code

        Button(action: tap) {
            Text("Button")
                .frame(minWidth: 0, maxWidth: .infinity)
                .background(Color.red)
        }
        .padding(.horizontal, 20)

Padding modifiers will allow you to have some space from the edge.

Keep in mind that the order of modifiers is essential. Because modifiers are functions that are wrapping the view below (they do not change properties of views)

Upvotes: 110

Sherwin Zadeh
Sherwin Zadeh

Reputation: 1452

Here's a pure SwiftUI solution where you want to fill the width of the parent but constrain the height to an arbitrary aspect ratio (say you want square images):

        Image("myImage")
            .resizable()
            .scaledToFill()
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .aspectRatio(16.0 / 9.0, contentMode: .fit)

Just replace 16.0 / 9.0 with whatever aspect ratio you want.

I spent about a day trying to figure this out because I didn't want to use GeometryReader or UIScreen.main.bounds (which isn't cross-platform)

Edit: Found an even simpler way.

Upvotes: 8

Tejas
Tejas

Reputation: 1048

Simple adding following to your code will make the button extend edge to edge. (You can add padding as well if you want)

.frame(minWidth: 0, maxWidth: .infinity)

The entire Button code will look like this:

struct ContentView : View {
    var body: some View {
        HStack {
            Button(action: {}) {
                Text("MyButton")
                    .color(.white)
                    .font(Font.system(size: 17))
            }
            .frame(minWidth: 0, maxWidth: .infinity)
            .padding(.top, 8)
            .padding(.bottom, 8)
            .background(Color.red, cornerRadius: 0)
        }
    }
}

Upvotes: 5

Matteo Pacini
Matteo Pacini

Reputation: 22846

You can use GeometryReader: https://developer.apple.com/documentation/swiftui/geometryreader

According to Apple:

This view returns a flexible preferred size to its parent layout.

enter image description here

It is a flexible solution, as it changes according to the parent layout changes.

Upvotes: 33

Argas
Argas

Reputation: 1527

I found one solution:

var body: some View {
    Button(action: {}) {
            HStack {
                Spacer()
                Text("MyButton")
                    .color(.white)
                    .font(Font.system(size: 17))
                Spacer()
            }
            .frame(height: 56)
            .background(Color.red, cornerRadius: 0)
        }.padding(20)
}

But I'm not sure that it is the best. May be someone will find more elegant solution/

Upvotes: 2

Related Questions