Search code examples
iosswiftuimobile

How to make a responsive container with a fixed initial size in SwiftUI?


I'm want to invest in my apps accessibility. So I want my UI to be able to support Dynamic Type.

The problem is that I have a Search Bar that needs to have a height of 43, except when the user has Dynamic Type on, then I need the search bar to grow vertically to support the larger text.

How do I make it responsive but also have a initial fixed size of 43?

struct SearchBar: View {
@Binding var searchText: String

var body: some View {
    RoundedRectangle(cornerRadius: 8)
        .foregroundStyle(.white)
        .overlay{
            HStack{
                Image(systemName: "magnifyingglass")
                    
                    .padding(.leading, 12)
                Rectangle()
                    .frame(width: 1,height: 23)
                    .padding(.vertical)
             
                TextField("Pesquisar...", text: $searchText)
                   
                Spacer()
            }
        }
        .shadow(radius: 6)
        
}

}


Solution

  • To support dynamic type, you can use a @ScaledMetric. Here I have made the divider's and the HStack's height scaled according to dynamic type.

    @Binding var searchText: String
    @ScaledMetric var searchBarHeight = 43
    @ScaledMetric var dividerHeight = 23
    
    var body: some View {
        RoundedRectangle(cornerRadius: 8)
            .foregroundStyle(.white)
            .overlay{
                HStack{
                    Image(systemName: "magnifyingglass")
                        
                        .padding(.leading, 12)
                    Rectangle()
                        .frame(width: 1,height: max(dividerHeight, 23))
                        .padding(.vertical)
                 
                    TextField("Pesquisar...", text: $searchText)
                       
                    Spacer()
                }
            }
            .shadow(radius: 6)
            .frame(height: max(searchBarHeight, 43))
        }
    }
    

    Here I have used max to keep a minimum height of 43 and 23, though I suggest you just use dividerHeight and searchBarHeight directly. Dynamic type isn't just for making text bigger, the user can also choose to make it smaller, and you should respect their choice.

    Another solution is to just add the rounded rectangle and the divider using background, making them automatically fit the size of the text field, as it changes.

    HStack{
        Image(systemName: "magnifyingglass")
            
            .padding(.leading, 12)
     
        TextField("Pesquisar...", text: $searchText)
            .padding(.vertical)
            .padding(.leading)
            .background(alignment: .leading) {
                Rectangle().frame(width: 1)
                    .padding(.vertical)
            }
           
        Spacer()
    }
    .background {
        RoundedRectangle(cornerRadius: 8)
            .foregroundStyle(.white)
            .shadow(radius: 6)
    }
    .frame(minHeight: 43)