SwiftUI iOS Widget – 一段时间后图像被裁剪

Rob*_*ler 5 ios swift widgetkit swiftui

我正在使用 SwiftUI 创建 iOS 14+ Widget,我面临着非常奇怪的情况。问题是我的小部件中只有一个“完整小部件”图像(也许值得注意的是,它是从互联网下载的,但在显示其已加载并注入时UIImage),该图像正确显示如下:

在此输入图像描述

但过了一段时间,更多的 iPhone 解锁 BOOM 后,我得到了这个:

在此输入图像描述

一些观察:

  • 家庭也会发生这种情况systemLarge- 图像宽度的相同百分比被裁剪
  • 图像始终以完全相同的宽度百分比水平裁剪
  • 当我的壁纸不仅仅是纯黑色时,裁剪部分也会填充黑色
  • 无论我有什么用户界面风格(浅色/深色),裁剪的部分都会填充黑色

为了方便起见,我创建了导致错误的最小示例:

所以,我有这个EntryView

struct EntryView: View {

    var viewModel: EntryViewModel

    var body: some View {
        Image(uiImage: image)
            .resizable()
            .scaledToFill()
    }
}
Run Code Online (Sandbox Code Playgroud)

用作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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Widget是包裹在WidgetBundle

@main
struct SomeWidgets: WidgetBundle {

    var body: some Widget {
        SomeWidget()
        SomeWidget()
    }
}
Run Code Online (Sandbox Code Playgroud)

也许我还应该展示负责下载图像的逻辑。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))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,我的布局或获取逻辑有问题吗?我缺少什么?

感谢您的任何帮助!

ARG*_*Geo 3

有几个问题是可能的。

1. 分辨率问题

问题通常源于您的小部件的图像分辨率。图像的分辨率(以像素为单位)必须与 Widget 的分辨率(以点为单位)相关。在下面的数据透视表中,您可以看到某些 iPhone 型号使用的分辨率(以点 (pts) 为单位)。点与像素不同,因为它们根据 PPI 改变大小。当分辨率为 时,1 点等于 1 像素163 PPI。Retina 时代之前的所有 iPhone 都是如此。然而今天,460 PPIiPhone 12 Pro 的 1 点等于横向 3 个像素、向下 3 个像素,即总共 9 个像素。

因此,对于 iPhone 13 Pro Max,中型小组件的图像大小不应超过 1092 x 510 像素(72 像素/英寸)。将 4K 源图像用于 iOS Widget 是非常不合适的。


模型 屏幕尺寸(磅) 小部件(分) 中等小部件(分) 大部件(分)
iPhone 13 Pro 最大 428×926 170×170 364×170 364×382
iPhone 11 414×896 169×169 360×169 360×379
iPhone 8 Plus 414×736 159×159 348×157 348×357
iPhone 12 专业版 390×844 158×158 338×158 338×354
iPhone X 375×812 155×155 329×155 329×345
iPhone 7 375×667 148×148 321×148 321×324
iPhone SE 320×568 141×141 292×141 292×311

2. 文件格式问题

小部件图像必须为 8 位.png格式。图像可以包含 Alpha 通道,但不应包含任何透明区域(即 Alpha 通道应为 100% 白色)。

3.调度QoS.QoSClass

使用最高优先级的服务质量,即.userInteractive情况:

DispatchQueue.global(qos: .userInteractive).async { ... }
Run Code Online (Sandbox Code Playgroud)

4.无效文件问题

尝试使用不同的.png. 您从互联网下载的映像很可能已损坏或损坏。图像可能因传输中断、恶意软件/病毒感染、SSD 坏块等而损坏。

5. 清理

有时,如果您发现功能不正常、索引编制或速度缓慢,则必须删除/清理构建。如果是这样,请从文件夹中删除项目的构建~/Library/Developer/。接下来,在 Xcode 中,在导航器面板中选择项目的图标,然后按Command- Shift-K快捷键来清理构建。

然后,关闭 Xcode,进入~/Library/Developer/Xcode/DerivedData/ModuleCache目录并删除缓存。

6.Xcode版本

在 Xcode 14 的发行版上运行您的项目。不要使用测试版。