SwiftUI iOS小部件-图像在一段时间后被裁剪

rt4zxlrg  于 2023-01-06  发布在  iOS
关注(0)|答案(3)|浏览(164)

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

但过了一段时间,在一些更多的iPhone解锁繁荣,我得到这个:

观察结果很少:

  • 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被 Package 在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))
            }
        }
    }
}

所以我的问题是,我的布局或获取逻辑有什么问题吗?我错过了什么?
谢谢你的帮助!

j9per5c4

j9per5c41#

有几个问题是可能的。

1.分辨率问题

问题通常源于小部件的图像分辨率。图像的分辨率(以像素为单位)必须与小部件的分辨率(以点为单位)相关。在下面的透视表中,你可以看到分辨率是多少(pts)部分iPhone型号使用。点与像素不同,因为它们会根据PPI改变大小。当分辨率为163 PPI时,1点等于1像素。Retina时代之前的所有iPhone都是如此,然而如今,在460 PPI的情况下,iPhone 12 Pro的1点等于横3像素,纵3像素,也就是总共9个像素。
因此,对于iPhone 13 Pro Max,中等小工具的图像大小不应超过1092 x 510像素(72像素/英寸)。iOS小工具使用4K源图像非常不合适。
| 型号|屏幕大小(pts)|小部件(pts)|中等小部件(pts)|大部件(pts)|
| - ------| - ------| - ------| - ------| - ------|
| iPhone 13专业版Max| 428 x 926| 170 x 170| 364 x 170| 364 x 382|
| iPhone 11系列|414 x 896| 169 x 169| 360 x 169| 360 x 379|
| iPhone 8升级版|414 x 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|
| 苹果手机7| 375 x 667| 148 x 148| 321 x 148| 321 x 324|
| iPhone SE系列|320 x 568| 141 x 141| 292 x 141| 292 x 311|

2.文件格式问题

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

3.调度QoS. QoS类

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

DispatchQueue.global(qos: .userInteractive).async { ... }

4.无效文件问题

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

5.清理

有时候,如果您发现构建版本运行不正常、索引不正确或速度缓慢,您必须删除/清理构建版本。如果是这样,请从~/Library/Developer/文件夹中删除项目的构建版本。接下来,在Xcode中,选择导航面板中的项目图标,然后按Command-Shift-K快捷键来清理构建版本。
然后,关闭Xcode,转到~/Library/Developer/Xcode/DerivedData/ModuleCache目录并删除缓存。

6. Xcode版本

在Xcode 14的发布版本上运行您的项目。不要使用beta。

xu3bshqb

xu3bshqb2#

我想告诉大家,安迪的回答很有道理。无论如何,对我来说,这个问题似乎在iOS 16上不再存在。所以,也许这是操作系统本身的一个错误,因为在代码没有任何变化的情况下,同样的代码在iOS 16上工作,而在iOS 15上不工作。

ctrmrzij

ctrmrzij3#

我有一个非常相似的问题,我想在这里张贴我的解决方案,以防有人有同样的一个,因为他们可能会像我一样在这个线程结束。
我的小部件具有添加自定义图像作为小部件背景的功能,如果图像太大,小部件将完全变灰,并带有编辑过的占位符(我猜是因为时间线提供程序无法提供这些大图像)。
因此,解决方案是通过编程将图像裁剪成一些预定义的大小。我发现,几乎所有设备的最大宽度和高度都是1024像素,这在所有iOS版本上都是可以接受的(iOS 16是撰写本文时的最新版本)。仅适用于iPhone 11和XR(它们有相同的屏幕)大小的高度/宽度824像素是我发现的第一个起作用的值。
我无法找到任何关于这些大小的文档,它们可能会在未来的iOS版本中更改。
如果使用存储在项目资源中的静态图像,则将824图像用于2x比例,将1024图像用于3x比例。

相关问题