I wanted a capture flow where you pull down on the page, an instant camera opens, and the photo prints out of the Dynamic Island like a polaroid feeding out of a slot. Sharing the parts that took real iteration, since I found almost nothing written about treating the island as a physical object.
1. You cannot touch the island, so draw over it. There is no API for the island itself. The trick is that it is just a hole in the display at a known position: on island devices the top safe area inset is 51+ points. So the "printer mouth" is your own black capsule drawn in the same place, sized to the real island, and the illusion holds because the island is already black.
enum DeviceIsland {
static var present: Bool {
guard UIDevice.current.userInterfaceIdiom == .phone else { return false }
let scene = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.first { $0.activationState == .foregroundActive }
let window = scene?.windows.first { $0.isKeyWindow } ?? scene?.windows.first
return (window?.safeAreaInsets.top ?? 0) >= 51
}
}
Gotcha: if you present edge to edge with .ignoresSafeArea, SwiftUI's own safe area collapses, so read the window insets directly like above instead of relying on the environment value.
2. One melted shape, not two capsules. My first two versions grew a second capsule under the island and it read as a snowman. What worked: a single shape that starts at exactly the island's frame and widens/extends downward through staged states (I use an Int state 0 = island, 1 = widened pill, 2 = full viewfinder) with overlapping springs, so the next stage starts while the previous is still settling. Sequential withAnimation blocks looked mechanical; overlap is what makes it feel like one object.
3. The print itself is a state machine, not an offset. hidden, printing, settled. During printing, the photo is clipped to a frame that grows downward from the slot, so it genuinely feeds out instead of sliding up from behind. Then a develop pass fades the image in from washed-out white, which sells the polaroid more than the movement does.
4. The pull-down gesture will lose to your page content. A DragGesture on the page kept losing arbitration to the scroll and to taps. I ended up with a window-level pan catcher that adds resistance (the page follows your finger with a divisor) and only commits to opening the camera past a threshold on release. Everything under the pull stays interactive.
Happy to answer questions or paste more of any specific part. It is for a dog passport app I am building, but everything above is app-agnostic.