Home > OS >  SwiftUI question about .padding view modifier from a lecture I saw
SwiftUI question about .padding view modifier from a lecture I saw

Time:07-11

So I was watching a lecture and I saw this:

Modifiers Remember that viewmodifier functions(like .padding) themselves return a View. That view, conceptually anyway, "contains" the View it's modifying.

Many of them just pass the size offered to them along(like .font or .foregroundColor). But it is possible for a modifier to be involved in the layout process itself.

For example the view returned by .padding(10) will offer the view that it is modifying a space that that is the same size as it was offered, but reduced by 10 points on each side. The view returned by .padding(10) would then choose a size for itself which is 10 points larger on all sides than the View it is modifying ended up choosing.

I don't fully understand this description because if I have some View I call T and I wanna add padding with T.padding(10) What is this saying will happen because this description doesn't fully make sense to me could someone maybe try to explain it a bit better..? Even though this does seem like a simple explanation to me it doesn't really click.

Edit for screenshot: Screenshot

CodePudding user response:

Think about this as calling .padding(10) on T, creates T1 view having 10pt larger size at each edge, places T at the center of this new T1 view, and returns new T1 view.

Thus every modifier can be considered as a factory of new container view which encloses original view and can affect it on purpose.

CodePudding user response:

In the example you provide, the HStack is a View that is made up of Card Views. The .foregroundColor(Color.orange) modifier takes the HStack View and returns a new View. Finally, the .padding(10) modifier takes that orange View and returns a new View adding padding of size 10 on all sides.

This slide is then explaining how the layout works, which is in the reverse direction. The first View in the chain of Views to be offered space is the last one, that is the View that results from adding padding. For instance, this View might be offered the entire screen if this were the top View in the ContentView. The padding view for layout purposes would then subtract 10 from all sides and offer the smaller space to the .foregroundColor() modifier. Since .foregroundColor() doesn't affect layout, it would offer this same size to the HStack View. The HStack would divide the offered space by the number of cards in the ForEach and offer this smaller view size to each of the Card Views.


An Example With Numbers

It might help your understanding to look at an example with real numbers.

Suppose this total view will fit into a space 200 wide by 240 tall, and there are 2 cards in the HStack. How big will each Card be? This is the question Layout is figuring out.

If you have 200 by 240 to work with, then the padding is going to take up space on all sides leaving a space of only 180 by 220 for the HStack to lay out its views. The HStack determines that it has 2 views laid out horizontally, so it offers half the space to each of the card views (90 by 220).

So, the padding is actually going to make the Card Views smaller because it is taking up some of the existing space.


Example to Play With in an iOS App

Try the following code in an iOS app. Run it as is and see what it looks like. Then change the padding to 100 and run it again. Notice that as the padding gets larger, the red and blue views get smaller.

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack {
            Color.red
            Color.blue
        }
        .padding(10)
    }
}

More Extensive Example with Slider to Adjust Padding

Here is a interactive example that shows the padding in Color.green that can be adjusted with the slider. The dimensions of the red and blue views are shown using GeometryReader.

struct ContentView: View {
    @State private var pad: CGFloat = 50
    
    var body: some View {
        VStack {
            HStack {
                GeometryReader { geo in
                    ZStack {
                        Color.red
                        Text("\(geo.size.width, specifier: "%.1f")x\(geo.size.height, specifier: "%.1f")").foregroundColor(.white)
                    }
                }
                GeometryReader { geo in
                    ZStack {
                        Color.blue
                        Text("\(geo.size.width, specifier: "%.1f")x\(geo.size.height, specifier: "%.1f")").foregroundColor(.white)
                    }
                }
            }
            .background(Color.yellow)
            .padding(pad)
        }
        .background(Color.green)
        HStack {
            Text("Padding =")
            HStack {
                Text("\(pad, specifier: "%.1f")")
                Spacer()
            }.frame(width: 50)
        }.foregroundColor(.green)
        Slider(value: $pad, in: 0...100).padding(.horizontal)
    }
}
  • Related