我正在使用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))
}
}
}
}
所以我的问题是,我的布局或获取逻辑有什么问题吗?我错过了什么?
谢谢你的帮助!
3条答案
按热度按时间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
情况:4.无效文件问题
尝试使用其他
.png
。很可能是您从互联网下载的映像已损坏或损坏。映像损坏可能是由于传输中断、恶意软件/病毒感染、SSD坏块等原因。5.清理
有时候,如果您发现构建版本运行不正常、索引不正确或速度缓慢,您必须删除/清理构建版本。如果是这样,请从
~/Library/Developer/
文件夹中删除项目的构建版本。接下来,在Xcode中,选择导航面板中的项目图标,然后按Command-Shift-K快捷键来清理构建版本。然后,关闭Xcode,转到
~/Library/Developer/Xcode/DerivedData/ModuleCache
目录并删除缓存。6. Xcode版本
在Xcode 14的发布版本上运行您的项目。不要使用beta。
xu3bshqb2#
我想告诉大家,安迪的回答很有道理。无论如何,对我来说,这个问题似乎在iOS 16上不再存在。所以,也许这是操作系统本身的一个错误,因为在代码没有任何变化的情况下,同样的代码在iOS 16上工作,而在iOS 15上不工作。
ctrmrzij3#
我有一个非常相似的问题,我想在这里张贴我的解决方案,以防有人有同样的一个,因为他们可能会像我一样在这个线程结束。
我的小部件具有添加自定义图像作为小部件背景的功能,如果图像太大,小部件将完全变灰,并带有编辑过的占位符(我猜是因为时间线提供程序无法提供这些大图像)。
因此,解决方案是通过编程将图像裁剪成一些预定义的大小。我发现,几乎所有设备的最大宽度和高度都是1024像素,这在所有iOS版本上都是可以接受的(iOS 16是撰写本文时的最新版本)。仅适用于iPhone 11和XR(它们有相同的屏幕)大小的高度/宽度824像素是我发现的第一个起作用的值。
我无法找到任何关于这些大小的文档,它们可能会在未来的iOS版本中更改。
如果使用存储在项目资源中的静态图像,则将824图像用于2x比例,将1024图像用于3x比例。