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.
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
View
s. 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 View
s 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
View
s.
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
View
s 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)
}
}