Exploring MusicKit and Apple Music API
Unlock the full power of MusicKit & Apple Music APIs in your apps with the best guide! Use code musickit-blog for a limited-time 35% discount!
Chroma Game uses a tab bar to list all the screens. For v2, I’m presenting all the views using the fullScreenCover
modifier.
While playing the game, due to the habit of swiping down to close the modal, I was missing the implementation in fullScreenCover
, something that we get out of the box when using the sheet
modifier. I want a fullScreenCover
that supports the swipe feature that sheet
offers.
Apple Music uses this on the now playing screen, and I love the transition:
How do you go about creating a draggable full-screen view like the Apple Music now playing screen using #SwiftUI? pic.twitter.com/H0oZ0ePAWS
— Rudrank Riyam (@rudrankriyam) January 22, 2022
DragGesture
As a temporary workaround, I’m adding a DragGesture
that calculates the difference between the start and last locations when the drag ends.
After some manual testing, I used the arbitrary value 150 to know that it was a full drag and the screen should dismiss.
Sample Example
Here’s an example to use fullScreenCover
with drag gesture:
struct SampleView: View {
@State private var showCoverView = false
var body: some View {
Button("PRESENT") {
showCoverView.toggle()
}
.fullScreenCover(isPresented: $showCoverView) {
CoverView()
}
}
}
struct CoverView: View {
/// Use @Environment(\.presentationMode) private var presentationMode for iOS 14 and below
@Environment(\.dismiss) private var dismiss
var body: some View {
Button("DISMISS") {
/// Use presentationMode.wrappedValue.dismiss() for iOS 14 and below
dismiss()
}
.gesture(
DragGesture().onEnded { value in
if value.location.y - value.startLocation.y > 150 {
/// Use presentationMode.wrappedValue.dismiss() for iOS 14 and below
dismiss()
}
}
)
}
}
Example from Chroma Game
Here’s a stripped implementation of the HomeView
where the view model contains an enum GameModeDestination
that switches between RGB and HSB view.
struct HomeView: View {
@EnvironmentObject var viewModel: HomeViewModel
var body: some View {
VStack {
Text("MAIN VIEW IMPLEMENTATION")
/// Stripped implementation of Home View
Button("PRESENT RGB") {
viewModel.gameDestination = .rgb
}
}
.fullScreenCover(
item: $viewModel.gameDestination,
onDismiss: viewModel.didDismiss) { item in
switch item {
case .rgb: RGBView(viewModel: viewModel.new)
case .hsb: HSBView(viewModel: viewModel.new)
}
}
}
}
ContainerView
has a dismiss button on the top, similar to Apple Music now playing screen:
public struct DismissButton: View {
var action: () -> ()
public init(_ action: @escaping () -> ()) {
self.action = action
}
public var body: some View {
Button(action: action) {
RoundedRectangle(cornerRadius: 16)
.fill(Color.gray)
.frame(width: 50, height: 5)
}
}
}
Here’s the implemention in ContainerView
:
struct ContainerView: View {
@Environment(\.presentationMode) var presentation
@ObservedObject var viewModel: MainViewModel
var body: some View {
VStack {
DismissButton { dismiss() }
Text("IMPLEMENTATION")
}
.gesture(
DragGesture().onEnded { value in
if value.location.y - value.startLocation.y > 150 {
dismiss()
}
}
)
}
private func dismiss() {
viewModel.invalidateTimer()
viewModel.dismiss()
presentation.wrappedValue.dismiss()
}
}
And that provides an easy swipe to dismiss the full-screen cover!
Conclusion
The’ DragGesture’ solution is a simple way to add a swipe to your full-screen cover, compared to what we have for the sheet
modifier.
The way how the parent view is enlarged while you’re dismissing the now playing screen view on Apple Music is what I intend to achieve in the future. I probably will have to see if there’s a way to use UIKit.
Tag @rudrankriyam on Twitter if you have already implemented something similar!
Thanks for reading, and I hope you’re enjoying it!
Exploring MusicKit and Apple Music API
Unlock the full power of MusicKit & Apple Music APIs in your apps with the best guide! Use code musickit-blog for a limited-time 35% discount!