skip to Main Content

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)
            }
        }
    }

2

Answers


  1. 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)
    
    Login or Signup to reply.
  2. 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)
            }
        }
    ``
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search