swiftui - 如何使用来自 url 的图像平滑滚动?
问题描述
我想做一个无限滚动的帖子视图。我正在使用 ScrollView + LazyVStack(如果我使用 List,那么行为是相同的)。此示例中的 Row 类似于我的实际项目中的 Row - 文本,然后是图片,然后是垂直堆栈中的更多文本。问题是当我滚动时,当图片出现时,开始抽搐。我注意到,如果你只留下图片并移除 VStack,那么抽搐就会减少,但它们仍然存在。在这个例子中,我使用的是来自 ios 15 的 AsyncImage,但对于来自 Nuke、SDWebImage 和其他的图片的行为相同。如何在不抽搐的情况下平滑滚动?
import SwiftUI
struct ContentView: View {
let urls: [URL] = [
URL(string: "https://klike.net/uploads/posts/2019-05/1556945414_2.jpg")!,
URL(string: "https://klike.net/uploads/posts/2018-12/1544426537_1.jpg")!,
URL(string: "https://klike.net/uploads/posts/2018-12/1544426563_6.jpg")!,
URL(string: "https://klike.net/uploads/posts/2018-12/1544426524_3.jpg")!,
URL(string: "https://klike.net/uploads/posts/2018-12/1544426502_5.jpg")!,
URL(string: "https://klike.net/uploads/posts/2018-12/1544426571_23.jpg")!,
URL(string: "https://klike.net/uploads/posts/2018-12/1544426508_4.jpg")!,
URL(string: "https://klike.net/uploads/posts/2018-12/1544426506_2.jpg")!,
URL(string: "https://klike.net/uploads/posts/2018-12/1544426569_9.jpg")!
]
var body: some View {
ScrollView {
LazyVStack {
ForEach(urls, id: \.self) { url in
Row(url: url)
}
}
}
}
}
struct Row: View {
let url: URL
let width = UIScreen.main.bounds.width
var body: some View {
VStack(spacing: 0) {
Text(url.absoluteString)
.font(.body)
// Here can be Nuke, SDWebImage or something else
AsyncImage(url: url) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
ProgressView()
}
.frame(width: width, height: width * 1.666666666666667) // <- 800/480 image size
Text(url.absoluteString)
.font(.callout)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
解决方案
当用户滚动时,每次可见一行时,应用程序都会重复请求相同的图像。因此,我相信您需要缓存下载的图像。
- Nuke 异步镜像组件:https ://github.com/kean/NukeUI
- Nuke 文档:https ://kean.blog/nuke/guides/caching
- Nuke ScrollViewPrefetching:https ://kean.blog/nuke/guides/prefetching (提供预取功能的自定义组件)
推荐阅读
- javascript - 如何使用 amqp 库在“设置结构”之外重用 RabbitMQ 连接和通道?
- java - 在 Eclipse 中构建期间发生错误
- c# - 无法使用 ADO.NET 连接架构从 SQL Server 读取数据
- docker - 在启动时将机密添加到保管库容器
- redgate - Redgate 源代码控制 - 如何判断 Db 链接到的 Git 存储库的哪个存储库?
- java - 通过给定的 x 和 y 笛卡尔点和以米为单位的半径计算面积
- database - 如何从组合框中获取所选选项以在下一页的文本框中显示该选项的信息?
- hibernate - Query.getResultList() 即使sql表有行也不返回结果
- ruby-on-rails - 未初始化的常量 DeviseTokenAuth::Concerns::User::BCrypt
- node.js - 我想将多个对象添加到 mongodb 上的单个文档