为什么 scrollTo 在 Int 而不是 Message 自定义对象类型上工作?
Why is scrollTo working on Int and not Message custom object type?
我用 Int 而不是消息尝试了相同的代码,它起作用了。
当我尝试使用消息对象时,出于某种原因它不喜欢它。即使 .id 是 UUID().
消息显示在 scrollView 中,可以手动滚动,但添加消息后不会自动滚动到底部。
我已经尝试在 ForEach 中使用 .self 而不是 .id,翻转 ScrollView 和 ScrollViewReader 的顺序,不在 MessageRow 上使用 .id,在 scrollTo 中向下转换为 UUID,似乎没有任何效果...
我错过了什么?
提前致谢!
ScrollViewReader { scrollView in
ScrollView(.vertical) {
LazyVStack {
ForEach(groupViewModel.messages) { message in
MessageRowView(message: message)
.padding(.leading)
}
}
.onAppear {
if !groupViewModel.messages.isEmpty {
if let last = groupViewModel.messages.last {
scrollView.scrollTo(last)
}
}
}
}
}
struct Message: Codable, Equatable, Identifiable, Hashable {
let id: UUID
let sender: FSUser
let message: String
let sendDate: Date
}
欢迎来到 Stack Overflow!你错过了一个简单的事实,即 message.id != message?.id
。您的 .id(message.id)
是 non-optional UUID,但是 groupViewModel.messages.last?.id
是可选的。因为它们不匹配,所以你不会得到卷轴。我会给你一个更好的。首先,您不需要使用 message.id
。您可以简单地比较消息本身,因为 Identifiable
符合 Equatable
。因此,您的代码变为:
ScrollViewReader { scrollView in
ScrollView(.vertical) {
LazyVStack {
// You can also skip id: \.id as message is Identifiable
ForEach(groupViewModel.messages) { message in
MessageRowView(message: message)
.id(message)
}
}
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now()) {
if !groupViewModel.messages.isEmpty {
// Use if let to unwrap the optional
if let last = groupViewModel.messages.last {
// Use the unwrapped value here
scrollView.scrollTo(last)
}
}
}
}
}
}
如果您还没有声明您的结构符合 Identifiable
,那就去做吧。我假设你这样做了,但你没有 post 那部分代码,所以我们没有 Minimal, Reproducible Example (MRE)。大多数问题都需要 MRE 才能得到解答,因此请确保您了解那是什么。
编辑:
在查看你的结构时,试试这个:
struct Message: Codable, Equatable, Identifiable, Hashable {
let id = UUID()
let sender: FSUser
let message: String
let sendDate: Date
}
您可以立即设置 UUID,因为它永远不会改变。此外,这在长 运行 中并不重要,但如果您符合 Identifiable
,您将获得 'Equatable' 一致性。
我用 Int 而不是消息尝试了相同的代码,它起作用了。
当我尝试使用消息对象时,出于某种原因它不喜欢它。即使 .id 是 UUID().
消息显示在 scrollView 中,可以手动滚动,但添加消息后不会自动滚动到底部。
我已经尝试在 ForEach 中使用 .self 而不是 .id,翻转 ScrollView 和 ScrollViewReader 的顺序,不在 MessageRow 上使用 .id,在 scrollTo 中向下转换为 UUID,似乎没有任何效果...
我错过了什么?
提前致谢!
ScrollViewReader { scrollView in
ScrollView(.vertical) {
LazyVStack {
ForEach(groupViewModel.messages) { message in
MessageRowView(message: message)
.padding(.leading)
}
}
.onAppear {
if !groupViewModel.messages.isEmpty {
if let last = groupViewModel.messages.last {
scrollView.scrollTo(last)
}
}
}
}
}
struct Message: Codable, Equatable, Identifiable, Hashable {
let id: UUID
let sender: FSUser
let message: String
let sendDate: Date
}
欢迎来到 Stack Overflow!你错过了一个简单的事实,即 message.id != message?.id
。您的 .id(message.id)
是 non-optional UUID,但是 groupViewModel.messages.last?.id
是可选的。因为它们不匹配,所以你不会得到卷轴。我会给你一个更好的。首先,您不需要使用 message.id
。您可以简单地比较消息本身,因为 Identifiable
符合 Equatable
。因此,您的代码变为:
ScrollViewReader { scrollView in
ScrollView(.vertical) {
LazyVStack {
// You can also skip id: \.id as message is Identifiable
ForEach(groupViewModel.messages) { message in
MessageRowView(message: message)
.id(message)
}
}
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now()) {
if !groupViewModel.messages.isEmpty {
// Use if let to unwrap the optional
if let last = groupViewModel.messages.last {
// Use the unwrapped value here
scrollView.scrollTo(last)
}
}
}
}
}
}
如果您还没有声明您的结构符合 Identifiable
,那就去做吧。我假设你这样做了,但你没有 post 那部分代码,所以我们没有 Minimal, Reproducible Example (MRE)。大多数问题都需要 MRE 才能得到解答,因此请确保您了解那是什么。
编辑:
在查看你的结构时,试试这个:
struct Message: Codable, Equatable, Identifiable, Hashable {
let id = UUID()
let sender: FSUser
let message: String
let sendDate: Date
}
您可以立即设置 UUID,因为它永远不会改变。此外,这在长 运行 中并不重要,但如果您符合 Identifiable
,您将获得 'Equatable' 一致性。