在 SwiftUI 中複製 Dynamic Island 動畫 為我們的 App 增添美感

在剛剛結束的年度 iPhone 發佈活動上,Apple 在 iPhone 14 Pro 推出了動態島(Dynamic Island),一個顯示新通知的創新方式。在這篇文章中,Aytuğ 會帶大家試著在 SwiftUI 中複製這個功能,為我們的 App 增添美感。
在 SwiftUI 中複製 Dynamic Island 動畫 為我們的 App 增添美感
Photo by SCREEN POST on Unsplash
在 SwiftUI 中複製 Dynamic Island 動畫 為我們的 App 增添美感
Photo by SCREEN POST on Unsplash
本篇原文(標題:Replicating the Dynamic Island Animation in SwiftUI)刊登於作者 Medium,由 Aytuğ 所著,並授權翻譯及轉載。

在剛剛結束的年度 iPhone 發佈活動上,Apple 在 iPhone 14 Pro 推出了「動態島」 (Dynamic Island),它是一個顯示新通知的創新方式。

我在 Xcode 14 release candidate 版本中體驗了這個新功能,希望在這篇文章中與大家分享。看完這篇文章,你就會發現我們可以簡單地在 SwiftUI 中複製這個功能。

當我們點擊按鈕時,動態島動畫就會啟動。我們會顯示動態島一段時間,然後再把它縮回原本的位置。

讓我們創建一個內容視圖,並添加一個按鈕,按鈕的操作就是發佈一個通知。

在此之前,我們需要先創建一個 NotificationModel

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            Text("Hello, Dynamic Island!")
            Button("Notify Me 🥳") {
                NotificationCenter.default.post(name: .init("NOTIFY"), object: NotificationModel(title: "Dynamic Island", content: "This is an example 😍"))
            }
        }
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
struct NotificationModel {
    var title: String
    var content: String
}

要在動態島上顯示視圖,我們需要忽略 safe area。

讓我們把這個視圖命名為 NotificationView,因為它是一個靈活的視圖,因此我們會把它放在 GeometryReader 中,然後設置忽略 safe area。

@main
struct DynamicIslandExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .overlay(alignment: .top) {
                    GeometryReader { proxy in
                        let size = proxy.size
                        NotificationView(size: size)
                            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
                    }
                    .ignoresSafeArea()
                }
        }
    }
}

動態島有 11 像素的 top padding,其寬度為 126,高度為 37.33。

所以,我們要在 notch 後面放一個視圖,然後用動畫放大它。

因為這是一個範例,我們會維持視圖原有的 state,只改變它的尺寸。在收到通知時,我們就會為動畫化視圖及設置通知。

另外,我們會把 isExpanded 設置為 true。

struct NotificationView: View {
    var size: CGSize
    @State var isExpanded: Bool = false
    @State var notification: NotificationModel?
    var body: some View {
        HStack {
          // any view for notify
        }

        .frame(width: isExpanded ? size.width - 22 : 126, height: isExpanded ? 120 : 37.33)
        .blur(radius: isExpanded ? 0 : 30)
        .opacity(isExpanded ? 1 : 0)
        .scaleEffect(isExpanded ? 1 : 0.5, anchor: .top)
        .background {
            RoundedRectangle(cornerRadius: isExpanded ? 50 : 63, style: .continuous)
                .fill(.black)
        }
        .clipped()
        .offset(y: 11)
        .onReceive(NotificationCenter.default.publisher(for: .init("NOTIFY"))) { output in
            guard let notification = output.object as? NotificationModel else { return }
            self.notification = notification
            withAnimation(.interactiveSpring(response: 0.7, dampingFraction: 0.7, blendDuration: 0.7)) {
                isExpanded = true

                DispatchQueue.main.asyncAfter(deadline: .now() + 2.2) {
                    withAnimation(.interactiveSpring(response: 0.7, dampingFraction: 0.7, blendDuration: 0.7)) {
                        isExpanded = false
                        self.notification = nil
                    }
                }
            }
        }
    }
}

當我們點擊按鈕時,就會看到動態島的動畫。

然後,我們就可以繪製想要的視圖。

我們可以隨時觸發及發送通知。

如果我們想確定設備有沒有動態島,就需要自己編寫一個擴充功能。

Apple 還沒有發佈這個擴充功能,我希望這個功能會在 iOS 16.1 中推出。

現在,我們可以把控件對照一下設備的名稱。

extension UIDevice {
    static var hasDynamicIsland: Bool {
        ["iPhone 14 Pro", "iPhone 14 Pro Max"].contains(current.name)
    }
}

動態島的動畫與普通視圖動畫似乎沒有什麼不同,我們已經完成實作了。

我們還可以自己設定想要的尺寸和外觀。對於使用者來說,在 App 中添加了動態島真的十分漂亮。

本篇原文(標題:Replicating the Dynamic Island Animation in SwiftUI)刊登於作者 Medium,由 Aytuğ 所著,並授權翻譯及轉載。
作者簡介:Aytuğ,Trendyol 的 iOS 開發者。
譯者簡介:Kelly Chan-AppCoda 編輯小姐。
作者
AppCoda 編輯團隊
此文章為客座或轉載文章,由作者授權刊登,AppCoda編輯團隊編輯。有關文章詳情,請參考文首或文末的簡介。
評論
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。