[英]SwiftUI iOS Widget – Image after some time gets cropped
我正在使用 SwiftUI 創建 iOS 14+ Widget,我面臨着非常奇怪的情況。 問題是我的小部件中只有一個“完整小部件”圖像(也許值得注意,它是從 inte.net 下載的,但在顯示它已經加載並注入為UIImage
)像那樣正確顯示:
但過了一段時間,在更多 iPhone 解鎖 BOOM 之后,我得到了這個:
一些觀察:
systemLarge
系列中 - 圖像寬度的相同百分比被裁剪為了方便起見,我創建了導致錯誤的最小示例:
所以,我有這個EntryView
struct EntryView: View {
var viewModel: EntryViewModel
var body: some View {
Image(uiImage: image)
.resizable()
.scaledToFill()
}
}
用作Widget
本身的內容
struct SomeWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(
kind: xxx,
provider: SomeWidgetTimelineProvider(xxx)
) { item in
view(for: item)
}
.configurationDisplayName(xxx)
.description(xxx)
.supportedFamilies([.systemMedium, .systemLarge])
}
private func view(for item: Item) -> some View {
Group {
switch item {
case .aaa(let xxx):
EntryView(viewModel: xxx)
case .bbb(let xxx):
EntryView(viewModel: xxx)
}
}
}
}
並且這個Widget
被包裹在WidgetBundle
中
@main
struct SomeWidgets: WidgetBundle {
var body: some Widget {
SomeWidget()
SomeWidget()
}
}
也許我還應該展示負責下載圖像的邏輯。 我只使用在后台隊列上調用的簡單Data(contentsOf:)
同步方法,然后在主隊列上調用TimelineProvider
的回調:
final class SomeWidgetTimelineProvider: TimelineProvider {
...
func getTimeline(in context: Context, completion: @escaping (Timeline<SomeEntry>) -> Void) {
getSomeModel { model in
prefetchImage(for: model) { result in
switch result {
case .success(let image):
completion(
Timeline(
entries: [.aaa(EntryViewModel(image: image)],
policy: .after(Date() + 30 * 60)
)
)
case .error(let error):
completion(
Timeline(
entries: [.bbb(xxx)],
policy: .after(Date() + 30 * 60)
)
)
}
}
}
}
private func prefetchImage(for model: SomeModel, completion: @escaping (Result<UIImage, Error>) -> Void) {
DispatchQueue.global(qos: .background).async {
guard
let imageURL = URL(string: model.imageUrl),
let data = try? Data(contentsOf: imageURL)
else {
DispatchQueue.main.async {
completion(.failure(xxx))
}
}
let image = UIImage(data: data)
DispatchQueue.main.async {
completion(.success(image))
}
}
}
}
所以我的問題是,我的布局或獲取邏輯有問題嗎? 我錯過了什么?
感謝您的任何幫助!
有幾個問題是可能的。
問題通常源於您的小部件的圖像分辨率。 以像素為單位的圖像分辨率必須與以點為單位的 Widget 分辨率相關。 在下面的 pivot 表中,您可以看到某些 iPhone 型號使用的分辨率(以點 (pts) 為單位)。 點與像素不同,因為它們會根據 PPI 改變大小。 當分辨率為163 PPI
時,1 點等於 1 個像素。 Retina 時代之前的所有 iPhone 都是如此。 然而,今天,在460 PPI
的情況下,iPhone 12 Pro 的 1 點等於 3 像素寬和 3 像素向下,或總共 9 像素。
因此,對於 iPhone 13 Pro Max,Medium Widget 的圖像尺寸不應超過 1092 x 510 像素(72 像素/英寸)。 為 iOS 小部件使用 4K 源圖像是非常不合適的。
Model | 屏幕尺寸(分) | 小部件 (pts) | 中等小部件(pts) | 大部件 (pts) |
---|---|---|---|---|
iPhone 13 專業版 | 428 x 926 | 170×170 | 364 x 170 | 364 x 382 |
iPhone 11 | 414 x 896 | 169×169 | 360 x 169 | 360 x 379 |
iPhone 8 加 | 414×736 | 159 x 159 | 348 x 157 | 348 x 357 |
iPhone 12 專業版 | 390 x 844 | 158×158 | 338 x 158 | 338 x 354 |
iPhone X | 375 x 812 | 155×155 | 329 x 155 | 329 x 345 |
iPhone 7 | 375 x 667 | 148×148 | 321×148 | 321×324 |
iPhone SE | 320 x 568 | 141×141 | 292 x 141 | 292×311 |
小部件圖像必須為 8 位.png
格式。 圖像可能包含 Alpha 通道,但不應包含任何透明區域(即 Alpha 通道應為 100% 白色)。
使用優先級最高的服務質量,即.userInteractive
案例:
DispatchQueue.global(qos: .userInteractive).async { ... }
嘗試使用不同的.png
。 您從 Internet 下載的圖像很可能已損壞或損壞。 圖像可能由於傳輸中斷、惡意軟件/病毒感染、SSD 壞塊等而損壞。
有時,如果您觀察到不正常的功能、索引或緩慢,您必須刪除/清理構建。 如果是這樣,請從~/Library/Developer/
文件夾中刪除您的項目構建。 接下來,在導航面板中的 Xcode、select 項目圖標中,然后按Command - Shift - K快捷方式來清理構建。
然后,關閉Xcode、go到~/Library/Developer/Xcode/DerivedData/ModuleCache
目錄並刪除緩存。
在 Xcode 14 的發布版本上運行您的項目。不要使用測試版。
只是讓任何人知道,安迪的回答有好處。 無論如何,對我來說,iOS 16 上似乎不再存在問題。所以這可能是操作系統本身的一個錯誤,因為沒有任何代碼更改,相同的代碼適用於 iOS 16 而不是 Z1BDF605991920DB11CBDF8508204
我遇到了一個非常相似的問題,我想在這里發布我的解決方案以防有人遇到相同的問題,因為他們可能會像我一樣在這個線程上結束。
我的小部件具有添加自定義圖像作為小部件背景的功能,如果圖像太大,小部件就會完全變成灰色,並帶有經過編輯的占位符(我假設是因為時間線提供商無法提供這些大圖像)。
所以解決方案是以編程方式將圖像裁剪為一些預定義的尺寸。 我發現對於幾乎所有設備,寬度或高度的最大尺寸1024 像素都完全可以,並且適用於每個 iOS 版本(iOS 16 是撰寫本文時的最新版本)。 僅對於iPhone 11 和 XR (具有相同的屏幕), 824 像素的高度/寬度是我發現的第一個有效值。
我找不到關於這些尺寸的任何文檔,它們可能會在未來的 iOS 版本中發生變化。
如果您使用存儲在項目資源中的 static 圖像,則將824圖像用於2x比例,將1024圖像用於3x比例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.