SwiftUI 框架

利用新的 ImageRenderer API 輕鬆把 SwiftUI 視圖轉換為圖像

iOS 16 為 SwiftUI 帶來的另一個 API 就是 ImageRenderer。我們可以利用這個 API,輕鬆把 SwiftUI 視圖轉換為圖像。在這篇文章中,我會帶大家試試使用這個新的 API。
利用新的 ImageRenderer API 輕鬆把 SwiftUI 視圖轉換為圖像
Photo by Amjith S on Unsplash
利用新的 ImageRenderer API 輕鬆把 SwiftUI 視圖轉換為圖像
Photo by Amjith S on Unsplash
In: SwiftUI 框架

iOS 16 為 SwiftUI 帶來的另一個 API 就是 ImageRenderer。有了這個 API,我們可以輕鬆把 SwiftUI 視圖轉換為圖像。這個實作十分簡單,讓我們利用想要轉換為圖像的視圖,來實例化 ImageRenderer 的實例:

let renderer = ImageRenderer(content: theView)

然後,我們就可以存取 cgImageuiImage 屬性,來取得轉換後的圖像。

一如以往,我喜歡利用範例來示範一個 API 的用法。較早之前,我們用了新的 Charts 框架來構建折線圖。這次,讓我們來看看如何讓使用者把折線圖保存為 Photo Album 中的圖像,並使用 ShareLink 進行分享。

重溫 Chart 視圖

swiftui-line-chart

首先,讓我們來重溫一下 ChartView 範例。我們使用了 Charts 框架的新 API 來構建一個有關氣溫的折線圖。程式碼如下:

var body: some View {
    VStack {
        Chart {
            ForEach(chartData, id: \.city) { series in
                ForEach(series.data) { item in
                    LineMark(
                        x: .value("Month", item.date),
                        y: .value("Temp", item.temperature)
                    )
                }
                .foregroundStyle(by: .value("City", series.city))
                .symbol(by: .value("City", series.city))
            }
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: .month)) { value in
                AxisGridLine()
                AxisValueLabel(format: .dateTime.month(.defaultDigits))

            }
        }
        .chartPlotStyle { plotArea in
            plotArea
                .background(.blue.opacity(0.1))
        }
        .chartYAxis {
            AxisMarks(position: .leading)
        }
        .frame(width: 350, height: 300)
        .padding(.horizontal)

    }
}

要使用 ImageRenderer,我們首先要把程式碼重構 (refactor) 為一個方法:

private func makeChartView() -> some View {
    VStack {
        Chart {
            ForEach(chartData, id: \.city) { series in
                ForEach(series.data) { item in
                    LineMark(
                        x: .value("Month", item.date),
                        y: .value("Temp", item.temperature)
                    )
                }
                .foregroundStyle(by: .value("City", series.city))
                .symbol(by: .value("City", series.city))
            }
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: .month)) { value in
                AxisGridLine()
                AxisValueLabel(format: .dateTime.month(.defaultDigits))

            }
        }
        .chartPlotStyle { plotArea in
            plotArea
                .background(.blue.opacity(0.1))
        }
        .chartYAxis {
            AxisMarks(position: .leading)
        }
        .frame(width: 350, height: 300)

        .padding(.horizontal)

    }
}

然後,讓我們宣告一個變數來保存視圖:

var chartView = ChartView()

利用 ImageRenderer 把視圖轉換為圖像

現在,我們可以把 Chart 視圖轉換為圖像了。我們要添加一個名為 Save to Photos 的按鈕,來把 Chart 視圖圖像儲存到 Photo Album 中。

讓我們如此實作按鈕:

var body: some View {

    VStack(spacing: 20) {
        chartView

        HStack {
            Button {
                let renderer = ImageRenderer(content: chartView)

                if let image = renderer.uiImage {
                    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
                }
            } label: {
                Label("Save to Photos", systemImage: "photo")
            }
            .buttonStyle(.borderedProminent)
        }
    }

}

在按鈕的閉包中,我們利用 chartView 來建立一個 ImageRenderer 的實例,並使用 uiImage 屬性來擷取生成的圖像。然後,讓我們調用 UIImageWriteToSavedPhotosAlbum 把圖像儲存到 Photo Album 中。

備註:我們需要在 info.plist 中添加一個 key  Privacy - Photo Library Usage Description,讓 App 可以把圖像儲存到內置的 Photo Album 中。

添加 Share 按鈕

swiftui-share-imagerenderer

在上一篇文章中,我們學了如何使用 ShareLink 來顯示一個 Share Sheet。我們可以搭配 ImageRanderer 使用,輕鬆地建立讓使用者分享 Chart 視圖的功能。

為方便起見,讓我們將渲染圖像 (rendered image) 的程式碼重構為一個獨立的方法:

@MainActor
private func generateSnapshot() -> UIImage {
    let renderer = ImageRenderer(content: chartView)

    return renderer.uiImage ?? UIImage()
}

這個 generateSnapshot 方法會把 chartView 轉換為圖像。

備註:如果你沒有用過 @MainActor,可以參考這篇文章

有了這個 helper 方法,我們就可以如此在 VStack 視圖中建立一個 ShareLink

ShareLink(item: Image(uiImage: generateSnapshot()), preview: SharePreview("Weather Chart", image: Image(uiImage: generateSnapshot())))
.buttonStyle(.borderedProminent)

現在,當我們點擊 Share 按鈕,App 就會擷取折線圖,並讓我們以圖像形式分享圖表。

swiftui-weather-chart-imagerenderer

調整圖像比例

你可能會發現渲染圖像的解析度有點低。ImageRenderer 類別有一個 scale 屬性,用來調整渲染圖像的比例。在預設情況下,這個屬性的值是 1.0。如果我們想提高圖像的解析度,可以將它設置為 2.03.0。或者,我們可以將值設置為螢幕比例:

renderer.scale = UIScreen.main.scale

總結

有了 ImageRenderer 類別,我們就可以簡單地把任何 SwiftUI 視圖轉換成圖像。如果你的 App 支援 iOS 16 以上的版本,就可以用這個新 API 為使用者建立一些方便的功能。除了渲染圖像外,我們還可以使用 ImageRenderer 來渲染 PDF 文件。詳情可以參閱 Apple 的官方文件

此外,Apple 也提供了一個更具體的渲染器:ChartRenderer,來將圖表匯出為圖像。我們會在之後的文章再探索這個類別。

譯者簡介:Kelly Chan-AppCoda 編輯小姐。
作者
Simon Ng
軟體工程師,AppCoda 創辦人。著有《iOS 17 App 程式設計實戰心法》、《iOS 17 App程式設計進階攻略》以及《精通SwiftUI》。曾任職於HSBC, FedEx等跨國企業,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda業務,致力於iOS程式教學、產品設計及開發。你可以到推特與我聯絡。
評論
更多來自 AppCoda 中文版
iOS 18 新API:使用 Navigation Transition 創建 Hero 動畫式過場
SwiftUI 框架

iOS 18 新API:使用 Navigation Transition 創建 Hero 動畫式過場

Apple 的工程師可能早已認識到,許多 iOS 開發者都希望能夠重現 App Store 應用程式中的優雅 Hero 動畫。由於從頭實現這種動畫通常需要耗費大量時間與精力,Apple 在 iOS 18 SDK 中納入了這項功能。 透過這次更新,你現在只需少量的程式碼就能在自己的應用程式中實現類似的動畫過渡效果。這項重大改進讓開發者能夠創造出更具視覺吸引力且流暢的過渡效果,
如何使用 Vision APIs 從圖像中辨識文字
AI

如何使用 Vision APIs 從圖像中辨識文字

Vision 框架長期以來一直包含文字識別功能。我們已經有詳細的教程,向你展示如何使用 Vision 框架掃描圖像並執行文字識別。之前,我們使用了 VNImageRequestHandler 和 VNRecognizeTextRequest 來從圖像中提取文字。 多年來,Vision 框架已經顯著演變。在 iOS 18 中,Vision
iOS 18更新:SwiftUI 新功能介紹
SwiftUI 框架

iOS 18更新:SwiftUI 新功能介紹

SwiftUI的技術不斷演進,每次更新都讓 iOS 應用程式開發變得更加便捷。隨著 iOS 18 Beta 的推出,SwiftUI 引入了多個令人興奮的新功能,使開發者僅需幾行程式碼即可實現出色的效果。 本教學文章旨在探索這個版本中的幾項主要改進,幫助你了解如何運用這些新功能。 浮動標籤列 (Floating Tab Bar)SwiftUI中的標籤視圖(Tab
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。