Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Aligning views to the leading & trailing edges of another view in a VStack

How do you align content to the leading and trailing edges of another view in a SwiftUI VStack?

I currently have the following SwiftUI code:

struct MyBlock: View {
    var body: some View {
        Rectangle().foregroundColor(.gray).frame(width: 80, height: 80)
    }
}

struct MyGridView: View {
    var body: some View {
        HStack(spacing: 16) {
            MyBlock()
            MyBlock()
            MyBlock()
        }                       
    }
}

struct PinPad: View {
    var body: some View {
        VStack {
            MyGridView()
            HStack {
                Button(action: {}, label: { Text("Left Align") })
                Spacer()
                Button(action: {}, label: { Text("Right Align") })
            }
        }
    }
}

The result renders like this:

Spacer consumes all the available space

But what I really want is for the "Left Align" Button to align with the left/leading edge of MyGridView and the "Right Align" Button to align to the right/trailing edge of the MyGridView.

Eg, like this:

Aligned Buttons

I'm obviously missing something very basic here as doing this with Auto-Layout in UIKit is trivial.

like image 399
orj Avatar asked Aug 22 '19 02:08

orj


People also ask

What are the alignment options available in SwiftUI?

SwiftUI Stack Alignment and Alignment Guides 1 Container Alignment. The most basic of alignment options when working with SwiftUI stacks is container alignment. ... 2 Alignment Guides. ... 3 Using the Alignment Guides Tool. ... 4 Custom Alignment Types. ... 5 Cross Stack Alignment. ... 6 ZStack Custom Alignment. ... 7 Summary. ...

Is it possible to design complex user interface layouts with SwiftUI?

Inevitably, when it comes to designing complex user interface layouts, it will be necessary to move beyond the standard alignment options provided with SwiftUI stack views.

How do I apply an alignment guide to a view?

Alignment guides are applied to views using the alignmentGuide () modifier which takes as arguments a standard alignment type and a closure which must calculate and return a value indicating the point within the view on which the alignment is to be based.

What are implicitly aligned views in Salesforce?

Views that do not have their own alignment guide are said to be implicitly aligned. When working with alignments it is important to remember that horizontal stacks (HStack) align child views vertically, while vertical stacks (VStack) align their children horizontally.


2 Answers

The first thing you need to do to troubleshoot layout issues, is to add borders on the views. This will let you see the real (and invisible) bounds of your views. The problem will become more clear:

enter image description here

In your case it can be easily fixed by wrapping it all inside a HStack and add some spacers:

enter image description here

struct PinPad: View {
    var body: some View {
        HStack {
            Spacer()
            VStack {
                MyGridView().border(Color.blue, width: 3)
                HStack {
                    Button(action: {}, label: { Text("Left Align") }).border(Color.red, width: 3)
                    Spacer()
                    Button(action: {}, label: { Text("Right Align") }).border(Color.red, width: 3)
                }
            }.border(Color.green, width: 3)
            Spacer()
        }
    }
}
like image 164
kontiki Avatar answered Sep 30 '22 03:09

kontiki


GeometryReader is a view that gives you access to the size and position of your parent

Defined a view called GeometryGetter,

struct GeometryGetter: View {

    @Binding var rect: CGRect

    var body: some View {
        return GeometryReader { geometry in
            self.makeView(geometry: geometry)
        }
    }

    func makeView(geometry: GeometryProxy) -> some View {
        DispatchQueue.main.async {
            self.rect = geometry.frame(in: .global)
        }

        return Rectangle().fill(Color.clear)
    }
}

Then change your code as below,

struct PinPad: View {

    @State private var rect: CGRect = CGRect()

    var body: some View {
        HStack {
            VStack {
                MyGridView().background(GeometryGetter(rect: $rect))
                HStack {
                    Button(action: {}, label: { Text("Left Align") })
                    Spacer()
                    Button(action: {}, label: { Text("Right Align") })
                }.frame(width: rect.width)
            }
        }
    }
}
like image 39
Ashish Avatar answered Sep 30 '22 02:09

Ashish