How to recreate Apple Music mini player transition in SwiftUI

Hello,

I am building an audio player app in SwiftUI and trying to recreate the behavior of Apple Music's mini player and full player.

I'm struggling to get the animation to seamlessly transition between the mini player and the full player. Currently, it feels disconnected and doesn't resemble the smooth animation seen in Apple Music.

What I want to achieve:

  • Full player that expands/collapses from/to the mini player
  • Smooth artwork transition between both states
  • Drag down to collapse the full player
  • Support both newer APIs like tabViewBottomAccessory and older iOS versions

Questions:

  • What is the best way to build this transition in SwiftUI?
  • Should I use matchedGeometryEffect or something else?
  • Should this be a custom container instead of fullScreenCover?
  • How would you support both new and older iOS versions?
  • What is the best way to implement drag to dismiss?

Thanks for any help!

Example code:

struct ContentView: View {
    @State private var isFullPlayerPresented = false

    var body: some View {
        TabView {
            Tab("Home", systemImage: "house") {
                Text("Home")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(.green)
            }
            Tab("Library", systemImage: "rectangle.stack.fill") {
                Text("Library")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(.brown)
            }
        }
        .tabViewBottomAccessory(isEnabled: !isFullPlayerPresented) {
            MiniPlayerView(isFullPlayerPresented: $isFullPlayerPresented)
        }
        .fullScreenCover(isPresented: $isFullPlayerPresented) {
            // Maybe it's not a full screen cover presentation in Apple Music?
            FullPlayerView(isFullPlayerPresented: $isFullPlayerPresented)
        }
    }
}

Mini player:

struct MiniPlayerView: View {
    @Binding var isFullPlayerPresented: Bool

    var body: some View {
        Button {
            isFullPlayerPresented = true
        } label: {
            HStack {
                Image(systemName: "photo")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 30, height: 30)
                    .clipShape(.rect(cornerRadius: 8))

                Spacer()
                Text("Tap to open full player")
                Spacer()

                Button("", systemImage: "play.fill", action: {})
            }
            .padding(.horizontal)
            .padding(.vertical, 4)
        }
        .foregroundStyle(.white)
    }
}

Full player:

struct FullPlayerView: View {
    @Binding var isFullPlayerPresented: Bool

    var body: some View {
        // This art work needs to snaps to the artwork in mini player
        Image(systemName: "photo")
            .resizable()
            .scaledToFit()
            .frame(width: 250, height: 250)
            .clipShape(.rect(cornerRadius: 20))
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(.red)
            .overlay(alignment: .topTrailing) {
                Button(role: .close) {
                    isFullPlayerPresented = false
                }
                .foregroundStyle(.white)
                .padding()
            }
    }
}
How to recreate Apple Music mini player transition in SwiftUI
 
 
Q