skip to Main Content

I have created a custom header view and would like to place the text horizontally centered. However even with HStack and Spacer on the left and a button on the right, my text doesn’t get horizontally centered. Adding code and expected screenshot and screenshot of how the output of my code looks.

Code:

private var headerView: some View {
    VStack(spacing: 0) {
        HStack {
            Spacer() // Tried replacing Spacer with Text(""), but then below scrollview width becomes very small.
            ScrollView(.horizontal, showsIndicators: false) {
                VStack(spacing: 0) {
                    Text("PXL_458345883_54815348358")
                        .font(
                            Font.custom("SF Pro Text", size: 17)
                              .weight(.semibold)
                          )
                        .multilineTextAlignment(.center)
                        .foregroundColor(.black)
                    HStack(alignment: .center) {
                        Text("JPG Image").font(.subheadline).foregroundColor(Color.gray)
                        VStack(alignment: .center) {
                            Spacer()
                            Text(verbatim: "u{002E}").font(.subheadline.bold()).foregroundColor(Color.gray)
                            Spacer()
                        }
                        Text("405 KB").font(.subheadline).foregroundColor(Color.gray)
                    }
                }.frame(maxWidth: .infinity, alignment: .center)
            }
            
            Spacer()
            Button {
                // button action
            } label: {
                Text("Done").font(.body.bold())
            }
            .frame(maxWidth: .infinity, alignment: .trailing)
            .padding(.trailing, 20.0)
        }
        .padding(.top, 10.0)
        .padding(.bottom, 5.0)
    }
}

Expected – Something like what’s highlighted in purple except in my case file name is long, so I have wrapped in horizontal scroll and the file name should be centered aligned and not left aligned.

enter image description here

Outcome of my code – Apart from text in center of the header view, I also want the "dot" between "JPG Image" and "405 KB" to be vertically centered.

enter image description here

Output after trying @nickreps approach of adding GeometryReader. The text is now center for longer file names, but if the file name is smaller, then the text is left aligned. After wrapping VStack in GeometryReader, I tried .frame(width: geometry.size.width * 0.62, alignment: .center) and .frame(width: geometry.size.width * 0.62)

enter image description here
enter image description here

2

Answers


  1. The issue you’re seeing is due to the HStack splitting the two views within it equally. You need to specify a frame on the ScrollView of a specific size to make sure it has priority for that space inside the HStack.

    Below I’ve integrated an example with GeometryReader that sets the frame size of the scrollview to 80% of the HStack width. You can modify the value as needed.

    private var headerView: some View {
        GeometryReader { geometry in // Added geometry reader here
            VStack(spacing: 0) {
                HStack {
                    Spacer() // Tried replacing Spacer with Text(""), but then below scrollview width becomes very small.
                    ScrollView(.horizontal, showsIndicators: false) {
                        VStack(spacing: 0) {
                            Text("PXL_458345883_54815348358")
                                .font(
                                    Font.custom("SF Pro Text", size: 17)
                                        .weight(.semibold)
                                )
                                .multilineTextAlignment(.center)
                                .foregroundColor(.black)
                            HStack(alignment: .center) {
                                Text("JPG Image").font(.subheadline).foregroundColor(Color.gray)
                                VStack(alignment: .center) {
                                    Spacer()
                                    Text(verbatim: "u{002E}").font(.subheadline.bold()).foregroundColor(Color.gray)
                                    Spacer()
                                }
                                Text("405 KB").font(.subheadline).foregroundColor(Color.gray)
                            }
                        }
                        .frame(maxWidth: .infinity, alignment: .center)
                        
                    }
                    .frame(width: geometry.size.width * 0.8) // <--- here!!
                    Button {
                        // button action
                    } label: {
                        Text("Done").font(.body.bold())
                    }
                    .frame(maxWidth: .infinity, alignment: .trailing)
                    .padding(.trailing, 20.0)
                }
                .padding(.top, 10.0)
                .padding(.bottom, 5.0)
            }
        }
    }
    

    enter image description here

    Login or Signup to reply.
  2. Try putting the ScrollView with the (possibly) long text in an overlay:

    struct ContentView: View {
    
        private let theFilename = "PXL_458345883_54815348358"
    
        private var headerView: some View {
            HStack {
                VStack(spacing: 0) {
                    Text(theFilename)
                        .lineLimit(1)
                        .hidden()
                        .overlay {
                            ScrollView(.horizontal, showsIndicators: false) {
                                Text(theFilename)
                                    .lineLimit(1)
                                    .fixedSize(horizontal: true, vertical: true)
                            }
                        }
                        .font(
                            Font.custom("SF Pro Text", size: 17)
                                .weight(.semibold)
                        )
                        .foregroundColor(.black)
                    HStack {
                        Text("JPG Image").font(.subheadline)
                        Text(verbatim: "u{002E}")
                            .font(.subheadline.bold())
                            .offset(y: -4)
                        Text("405 KB").font(.subheadline)
                    }
                    .foregroundColor(.gray)
                }
                .frame(maxWidth: .infinity)
                Button {
                    // button action
                } label: {
                    Text("Done")
                        .font(.body.bold())
                }
            }
            .padding(.horizontal, 20.0)
            .padding(.top, 10.0)
            .padding(.bottom, 5.0)
        }
    
        var body: some View {
            headerView
        }
    }
    

    Screenshot

    More notes:

    • This draws on the solution I gave as an answer to the question "How to keep the ScrollView height to the minimum necessary in SwiftUI?".
    • Suggest using a y-offset to make the dot vertically centered in the HStack on the second row.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search