Search code examples
listviewswiftuialignmenttoggleios18

SwiftUI: Toggle inside List does not use full width in iOS 18


I'm trying to have a View inside a List occupying the full width of the screen. The standalone view does. Once in a List, it takes ~60% of the available space.

I tried already to use .frame(minWidth: .infinity)on the List or on the View, but it does not change anything. I also tried various styles for the List, without success.

struct TodoRow: View {
    @Binding var todo: Todo

    var body: some View {
        Toggle(isOn: $todo.isDone) {
            Text(todo.content ?? "")
        }
        .border(.red)
        .toggleStyle(.switch)
    }
}

struct ContentView: View {
   @State var td1 = Todo(content: "Hello Todo World 20240706T15:23:42.256Z", isDone: false)

    var body: some View {
        
        List {
            TodoRow(todo: $td1)
            TodoRow(todo: $td1)
        }
        .border(.green)
        
        TodoRow(todo: $td1)
            .border(.blue)
    }
}

Screenshot


Solution

  • This is a change in the default Toggle style in iOS 18 which wraps the switch below the text where needed.

    You can recreate the old style easily like:

    struct TodoRow: View {
        @Binding var todo: Todo
    
        var body: some View {
            HStack { // 👈 Make sure this will be stacked horizontally
                Text(todo.content ?? "") // 👈 Add the leading text in place
                    .frame(maxWidth: .infinity, alignment: .leading) // 👈 Make it always fill the space
                Toggle(isOn: $todo.isDone) {
                    Text(todo.content ?? "")
                }
                .labelsHidden() // 👈 Hides the default label keeping the accessibility stuff
            }
            .toggleStyle(.switch)
        }
    }
    

    Demo