How to organize layout with ControlGroup in SwiftUI


Greetings, traveler!

Have you ever heard about a ControlGroup in SwiftUI? This tool can help create groups of UI components in SwiftUI Views, particularly SwiftUI Menus.

Example

We can create something like Stepper with this component.

struct ControlGroupView: View {
    var body: some View {
        ControlGroup {
            Button {
                
            } label: {
                Image(systemName: "plus")
            }
            
            Button {
            } label: {
                Image(systemName: "minus")
            }
        }
    }
}

We can also use some specific modifiers to create a desired layout.

struct ControlGroupView: View {
    var body: some View {
        ControlGroup {
            Button {
                
            } label: {
                Image(systemName: "plus")
            }
            
            Button {
            
            } label: {
                Image(systemName: "minus")
            }
        }
        .controlGroupStyle(.automatic)
    }
}

Menu

We can use the same approach to create a row for the SwiftUI Menu containing a control group.

First, let’s create regular menu items.

struct ContentView: View {
    
    private var menuView: some View {
        ForEach(0...3, id: \.self) { number in
            Button("Menu item \(number)") {}
        }
    }
    
}

Then, let’s create a player control view, which will be displayed in one line.

struct ContentView: View {    
    
    private var menuView: some View {
        ForEach(0...3, id: \.self) { number in
            Button("Menu item \(number)") {}
        }
    }
    
    private var playerView: some View {
        ControlGroup {
            Button {
                print("previous track")
            } label: {
                Image(systemName: "backward")
            }
            
            Button {
                print("play")
            } label: {
                Image(systemName: "play")
            }
            
            Button {
                print("next track")
            } label: {
                Image(systemName: "forward")
            }
        }        
    }
    
}

Now, let’s put it all together.

struct ContentView: View {
    
    var body: some View {
        Menu {
            menuView
            playerView
        } label: {
            Image(systemName: "line.horizontal.3.decrease.circle")
        }
    }
    
}

Nice!