What Is The Default Value of The Padding Modifier in Swift

What is the default value of the padding modifier in swift?

As far as I understood from Apple's documentation, there's no standard value and it's calculated based on some criteria by Apple. So, it may be different for different devices, accessibility settings of user, if user is using the app in side-by-side mode on iPad, etc...

Here is the documentation:

The set of edges along which to pad this view; if nil the specified or system-calculated amount is applied to all edges.

Left and right padding (not leading and trailing) in SwiftUI

Use @Environment(\.layoutDirection) to get the current layout direction (LTR or RTL) and use it to flip .leading and .trailing as needed.

Here’s a ViewModifier that wraps all that conveniently:

enum NoFlipEdge {
case left, right
}

struct NoFlipPadding: ViewModifier {
let edge: NoFlipEdge
let length: CGFloat?
@Environment(\.layoutDirection) var layoutDirection

private var computedEdge: Edge.Set {
if layoutDirection == .rightToLeft {
return edge == .left ? .trailing : .leading
} else {
return edge == .left ? .leading : .trailing
}
}

func body(content: Content) -> some View {
content
.padding(computedEdge, length)
}
}

extension View {
func padding(_ edge: NoFlipEdge, _ length: CGFloat? = nil) -> some View {
self.modifier(NoFlipPadding(edge: edge, length: length))
}
}

Use it like you would the standard padding modifiers:

Text("Text")
.padding(.left, 10)

SwiftUI - Ternary operator on padding modifier crashes program

Try this:

ForEach(0..<arr.count) { i in
ZStack {
...
}
.padding(.top, getPadding(i))

// I use i later in this code
...
}
func getPadding(_ i: Int) -> CGFloat {
if i == 0 {
return CGFloat(70)
}

return CGFloat(0)
}

How to remove the left and right Padding of a List in SwiftUI?

It looks like .listRowInsets doesn't work for rows in a List that is initialised with content.

So this doesn't work:

List(items) { item in
ItemRow(item: item)
.listRowInsets(EdgeInsets())
}

But this does:

List {
ForEach(items) { item in
ItemRow(item: item)
.listRowInsets(EdgeInsets())
}
}

Remove default padding from List in SwiftUI

To achieve this you need to use ForEach inside List combined with .listRowInsets as in example below

demo

struct Demo: View {
var colors: [Color] = [.red, .blue, .yellow]
var body: some View {
List {
ForEach(colors, id: \.self) { color in
color
}.listRowInsets(EdgeInsets())
}
// Update: Different iOS versions have different
// default List styles, so set explicit one if needed
.listStyle(PlainListStyle())
}
}

SwiftUI container view - how to provide default value for a property?

You said “when I'd needed n optional arguments, I'd have to make n^2 initializers ...” It's worse than that, because it's 2^n (exponential), not n^2 (quadratic). But, n here is the number of generic arguments for which you want to provide defaults, which means n is usually quite small (1 for your SampleBgContainer).

You also said “I can't imagine this is how SwiftUI is implemented”, but yes, that's exactly how SwiftUI does it when SwiftUI wants to provide a default for a generic argument. For example, SwiftUI provides a Toggle initializer that lets you use a string instead of a View for the label. It converts the string into a Text for you, and it's declared like this:

extension Toggle where Label == Text {
public init(_ titleKey: LocalizedStringKey, isOn: Binding<Swift.Bool>)
}

Anyway, there is a solution to the exponential explosion of init overloads, and we can find it by looking at SwiftUI's Text.

You can tweak the appearance of a Text in lots of ways. For example, you can make it bold or italic, you can change the kerning or the tracking, and you can change the text color. But you don't pass any of these settings to Text's initializer. You do them all by calling modifiers on the Text. Some of modifiers (like foregroundColor) apply to any View, but others (like bold, italic, kerning, and tracking) are only available on Text directly.

You can use the same system: custom modifiers that work only on your type, instead of init arguments. This interface style lets you avoid the 2^n overload explosion.

First, omit all of the non-generic, defaultable arguments from init:

struct SampleContainer<Content: View, Background: View>: View {
var alignment: HorizontalAlignment = .leading
var padding: CGFloat = VisualStyle.stackItemPadding
var cornerRadius: CGFloat = VisualStyle.stackItemCornerRadius
var content: Content
var background: Background

init(
@ViewBuilder content: () -> Content,
@ViewBuilder background: () -> Background
) {
self.content = content()
self.background = background()
}

var body: some View {
VStack(alignment: alignment) {
content
}
.padding(.all, self.padding)
.frame(idealWidth: .infinity, maxWidth: .infinity)
.background(background)
.clipShape(RoundedRectangle(cornerRadius: self.cornerRadius))
}
}

Second, provide a single init overload that constrains all of the defaultable generic arguments to their default types. In your case, there's only one such argument:

extension SampleContainer where Background == Color {
init(
@ViewBuilder content: () -> Content
) {
self.content = content()
self.background = Color.white.opacity(0.05)
}
}

Finally, provide modifiers for changing the properties, including the generic arguments:

  private func with(_ mutate: (inout Self) -> ()) -> Self {
var copy = self
mutate(©)
return copy
}

func stackAlignment(_ alignment: HorizontalAlignment) -> Self {
return self.with { $0.alignment = alignment }
}

func stackPadding(_ padding: CGFloat) -> Self {
return self.with { $0.padding = padding }
}

func stackRadius(_ radius: CGFloat) -> Self {
return self.with { $0.cornerRadius = radius }
}

func stackBackground<New: View>(@ViewBuilder _ background: () -> New) -> SampleContainer<Content, New> {
return .init(content: { content }, background: background)
}
}

Use it like this for default settings:

  SampleContainer {
Text("default settings only")
Text("hello world")
}

Or use the modifiers to customize it:

  SampleContainer {
Text("custom settings only")
Text("hello world")
}
.stackAlignment(.trailing)
.stackPadding(2)
.stackRadius(20)
.stackBackground {
LinearGradient(
colors: [
Color.red,
Color.blue,
],
startPoint: .top,
endPoint: .bottom
)
}

How to add if else statement on padding? SwiftUI

Use ternary operator right inside modifier, like

.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
.padding(.top, showBar ? 0 : -15) // << here !!


Related Topics



Leave a reply



Submit