I have a view that consists of multiple UI elements in a HStack:

  1. Time
  2. Icon
  3. Summary
  4. Divider
  5. Value

I want 1), 2) and 5) to take up no more space than necessary i.e. I don't need to intervene.

With 3) and 4) I would like for the summary to take up as much space as it needs at the expense of the divider that follows. If that means none, or a minimal amount, of the divider can appear then so be it. However, despite my best attempts, the summary only seems to take up a certain amount of space, causing its content to run over multiple lines to ensure the divider always appears. Giving it a layoutPriority helped slightly.

I don't want to give it a minWidth because I'd like for the distribution of width to be dynamically arranged based on the content.

Here's the code:

HStack {
    
    // MARK: Time
    HStack {
        VStack {
            Spacer()
            Text("9am")
            Spacer()
        }
    }.padding(.horizontal, 4)
    .padding(.vertical)
    .background(Color.blue.opacity(0.2))
    .cornerRadius(8)
         
    VStack {
        HStack {
            
            // MARK: Icon
            Image(systemName: "cloud.drizzle.fill")
            .font(Font.title2)
            
            // MARK: Summary
            VStack {
                HStack {
                    Text("Humid and overcast")
                        .padding(.trailing, 2)
                        .background(Color.white)
                        .layoutPriority(100)
                    Spacer()
                }
            }
            
            // MARK: Line
            VStack {
                Spacer()
                Divider()
                Spacer()
            }
            
            // MARK: Values
            VStack {
                Text(String(22.66))
                Text("25%")
                    .foregroundColor(Color.black)
                    .background(Color.white)
            }
            
            Spacer()
        }
    }
}

And this is what it looks like:

enter image description here

As you can the text runs over multiple lines when there's enough room for it to fit on one line, as long as the divider that followed accommodated the longer text by being shorter.

2

There are 2 best solutions below

1
On BEST ANSWER

Fixed size should be helpful here. Tested with Xcode 12.1 / iOS 14.1

demo

struct TestLongHStack: View {
    var body: some View {
        HStack {
            
            // MARK: Time
            HStack {
                VStack {
                    Spacer()
                    Text("9am")
                    Spacer()
                }
            }.padding(.horizontal, 4)
            .padding(.vertical)
            .background(Color.blue.opacity(0.2))
            .cornerRadius(8)
            
            VStack {
                HStack {
                    
                    // MARK: Icon
                    Image(systemName: "cloud.drizzle.fill")
                        .font(Font.title2)
                    
                    // MARK: Summary
                    VStack {
                        HStack {
                            Text("Humid and overcast").fixedSize()  // << here !!
                                .padding(.trailing, 2)
                                .background(Color.white)
                                .layoutPriority(100)
                            Spacer()
                        }
                    }
                    
                    // MARK: Line
                    VStack {
                        Spacer()
                        Divider()
                        Spacer()
                    }
                    
                    // MARK: Values
                    VStack {
                        Text(String(22.66)).bold().italic()
                        Text("25%").font(.footnote)
                            .foregroundColor(Color.black)
                            .background(Color.white)
                    }
                    
                    Spacer()
                }
            }
        }.fixedSize(horizontal: false, vertical: true)
    }
}
1
On

There is a lot of VStack / HStack / Divider / Spacer going on that can be optimized using a few HStack properties. Below is the exact same display with much less layout code and getting rid of the whacky Divider element:

struct TesterView: View {
    var body: some View {

        HStack(alignment: .center, spacing: 10) {  // use alignment and spacing instead of all the VStack formatting
                
            // MARK: Time
            Text("9am")
                .padding(.vertical, 20).padding(.horizontal, 5) // specifically set a padding number instead of relying on default
                .background(Color.blue.opacity(0.2)
                                .cornerRadius(8))
                
            // MARK: Icon
            Image(systemName: "cloud.drizzle.fill")
                .font(.title2)
                        
            // MARK: Summary
            Text("Humid and overcast")
                .fixedSize(horizontal:true, vertical:false)
                .background(Color.white)
            
            // MARK: Line
            // note: Rectangle expands to fill space just like Divider, use .frame() to control its height
            // IMO relying on Divider to interpret its parent container and expand properly seems whacky and non-specific
            Rectangle()
                .fill(Color.black.opacity(0.2))
                .padding(.horizontal, 5)
                .frame(height:1)
                        
            // MARK: Values
            VStack {
                Text(String(22.66)).bold().italic()
                Text("25%").font(.footnote)
                    .foregroundColor(Color.black)
                    .background(Color.white)
            }
        }
        .padding(.horizontal, 20) // added HStack padding to push off screen edges
    }
}