Home > front end >  SwiftUI Handle different frame alignments in Stack
SwiftUI Handle different frame alignments in Stack

Time:05-28

I have several views in a VStack/ScrollView using SwiftUI, The text elements I want to be leading (not centered in the view) but the Image I want centered on the Y axis. I've tried using center alignment in the frame but not the image still aligned leading. I tried making the VStack not aligned to leading with the Text aligned leading in the frame, but it just aligned center.

What is the correct way to handle this?

var body: some View {
        GeometryReader { geo in
            VStack {
                ScrollView(.vertical, showsIndicators: false) {
                    VStack(alignment: .) {
                        Text(title: viewData.title, font: .bold, size: 22)
                            .padding(.top, 27)
                        Text(title: viewData.body1, font: .regular, size: 16)
                            .padding(.top, 4)
                            .frame(alignment: .center)
                        Image(viewData.headerImageName ?? "")
                            .padding(.top, 80)
                            .frame(width: 88, height: 91, alignment: .center)
                    }
                }
                .padding(.horizontal, 16)

                Spacer()
                Button(action: {
                    self.navigateToNext()
                }, label: {
                    Text(title: viewData.buttonTitle, font: .regular, size: 16)
                        .foregroundColor(.white)
                })
                .frame(width: geo.size.width - 32, height: 48, alignment: .center)
                .background(Color(UIColor.Green))
                .cornerRadius(8)
            }
        }
    }

CodePudding user response:

There are a few ways to get the alignment you're looking for. I've provided a few simplified examples below:

Option 1

/// Text and Image frame will be leading aligned
VStack(alignment: .leading) {
    Text("Title")
    
    Text("Body text")
    
    Image(systemName: "gear")
        .resizable()
        .scaledToFit()
        /// Width limited to 88 points
        .frame(width: 88)
        /// Put in the center of another frame that fills the width.
        .frame(maxWidth: .infinity)
}

Option 2

/// Text frames and Image will be center aligned.
VStack {
    Text("Title")
        /// Put on the leading edge of a frame that fills the width
        /// This frame is then aligned to the center of the VStack.
        .frame(maxWidth: .infinity, alignment: .leading)
    
    Text("Body text")
        /// Put on the leading edge of a frame that fills the width
        .frame(maxWidth: .infinity, alignment: .leading)
    
    Image(systemName: "gear")
        .resizable()
        .scaledToFit()
        .frame(width: 88)
}

Option 3

/// HStack and Image will be center aligned.
VStack {
    HStack {
        /// Text will be leading aligned.
        VStack(alignment: .leading) {
            Text("Title")
            Text("Body text")
        }
        
        /// Spacer takes up remaining horizontal space.
        Spacer()
    }
    
    Image(systemName: "gear")
        .resizable()
        .scaledToFit()
        .frame(width: 88)
}

Additionally, the GeometryReader is not required on the overall frame.

This line:

.frame(width: geo.size.width - 32, height: 48, alignment: .center)

Can be replaced by:

.padding(.horizontal, 32)
.frame(height: 48)

CodePudding user response:

here is an approach (and IMHO you don't need geometryReader):

    var body: some View {
        VStack {
            ScrollView(.vertical, showsIndicators: false) {
                VStack(alignment: .leading) {
                    Text("viewData.title")
                        .font(.system(size: 22, weight: .bold))
                        .padding(.top, 27)
                    
                    Text("viewData.body1")
                        .font(.system(size: 16, weight: .regular))
                        .padding(.top, 4)
                    
                    Image(systemName: "sun.max")
                        .resizable()
                        .frame(width: 88, height: 91)
                        .frame(maxWidth: .infinity, alignment: .center) // here
                }
            }
            .padding(.horizontal)
            
            Spacer()
            
            Button(action: {
                //                        self.navigateToNext()
            }, label: {
                Text("viewData.buttonTitle")
                    .font(.system(size: 16, weight: .regular))
                    .foregroundColor(.white)
            })
            .frame(height: 48)
            .frame(maxWidth: .infinity, alignment: .center)
            .background(Color(UIColor.green))
            .cornerRadius(8)
            .padding(.horizontal)
        }
    }
``
  • Related