LazyVGrid 列表中的单元格有时会消失
Posted
技术标签:
【中文标题】LazyVGrid 列表中的单元格有时会消失【英文标题】:Cell in List with LazyVGrid Disappears sometimes 【发布时间】:2021-10-31 01:08:40 【问题描述】:我有这个:
VStack
List
LazyVGrid(columns: gridItemLayout)
ForEach(viewModel.objects, id: \.fileGroupUUID) item in
AlbumItemsScreenCell(object: item, viewModel: viewModel, config: Self.config)
.onTapGesture
switch viewModel.changeMode
case .moving, .sharing, .moveAll:
viewModel.toggleItemToChange(item: item)
case .none:
object = item
viewModel.showCellDetails = true
.onLongPressGesture
viewModel.restartDownload(fileGroupUUID: item.fileGroupUUID)
// end ForEach
// end LazyVGrid
.listStyle(PlainListStyle())
.refreshable
viewModel.refresh()
.padding(5)
// Mostly this is to animate updates from the menu. E.g., the sorting order.
.animation(.easeInOut)
// Had a problem with return animation for a while: https://***.com/questions/65101561
// The solution was to take the NavigationLink out of the scrollview/LazyVGrid above.
if let object = object
// The `NavigationLink` works here because the `MenuNavBar` contains a `NavigationView`.
NavigationLink(
destination:
ObjectDetailsView(object: object, model: ObjectDetailsModel(object: object)),
isActive:
$viewModel.showCellDetails)
EmptyView()
.frame(width: 0, height: 0)
.disabled(true)
// end if
// end VStack
AlbumItemsScreenCell:
struct AlbumItemsScreenCell: View
@StateObject var object:ServerObjectModel
@StateObject var viewModel:AlbumItemsViewModel
let config: IconConfig
@Environment(\.colorScheme) var colorScheme
var body: some View
AnyIcon(model: AnyIconModel(object: object), config: config,
emptyUpperRightView: viewModel.changeMode == .none,
upperRightView:
UpperRightChangeIcon(object: object, viewModel: viewModel)
)
当用户点击其中一个单元格时,会导致导航到详细信息屏幕。有时当用户从该导航返回时,左上角的单元格会消失:
https://www.dropbox.com/s/mi6j2ie7h8dcdm0/disappearingCell.mp4?dl=0
我目前关于该问题的假设是,当该详细信息屏幕中的用户操作采取更改 viewModel.objects
的操作时,这会导致单元格消失问题。我很快就会检验这个假设。
----- 更新,11/1/21 ------
嗯,这个假设是错误的。我现在更清楚地了解了问题的结构。但仍然没有修复。
点击其中一个AlbumItemsScreenCell
s 导航到详细信息屏幕(我已添加到上面的代码中以显示这一点)。在详细信息屏幕中,用户操作可能会导致评论计数被重置,这会发送Notification
。
AlbumItemsScreenCell
中的模型侦听这些通知(针对特定单元格)并重置单元格上的徽章。
这是那个模型:
class AnyIconModel: ObservableObject, CommentCountsObserverDelegate, MediaItemBadgeObserverDelegate, NewItemBadgeObserverDelegate
@Published var mediaItemBadge: MediaItemBadge?
@Published var unreadCountBadgeText: String?
@Published var newItem: Bool = false
var mediaItemCommentCount:CommentCountsObserver!
let object: ServerObjectModel
var mediaItemBadgeObserver: MediaItemBadgeObserver!
var newItemObserver: NewItemBadgeObserver!
init(object: ServerObjectModel)
self.object = object
// This is causing https://***.com/questions/69783232/cell-in-list-with-lazyvgrid-disappears-sometimes
mediaItemCommentCount = CommentCountsObserver(object: object, delegate: self)
mediaItemBadgeObserver = MediaItemBadgeObserver(object: object, delegate: self)
newItemObserver = NewItemBadgeObserver(object: object, delegate: self)
unreadCountBadgeText
在收到Notification
时被观察者更改(在主线程上)。
因此,总而言之,单元格上的徽章会发生变化,而单元格的屏幕不会显示 - 会显示详细信息屏幕。
【问题讨论】:
你能加入minimal reproducible example吗?否则,任何人都无法运行您的代码并尝试帮助调试它。 看起来AlbumItemsScreenCell
中的 2 @StateObject
应该是 @ObservedObject
。一旦您向我们展示了一个可重现的最小示例,我们就会了解更多。
【参考方案1】:
我一直在使用以下条件修饰符:
extension View
public func enabled(_ enabled: Bool) -> some View
return self.disabled(!enabled)
// https://forums.swift.org/t/conditionally-apply-modifier-in-swiftui/32815/16
@ViewBuilder func `if`<T>(_ condition: Bool, transform: (Self) -> T) -> some View where T : View
if condition
transform(self)
else
self
在AlbumItemsScreenCell
上显示徽章。
原来的徽章是这样的:
extension View
func upperLeftBadge(_ badgeText: String) -> some View
return self.modifier(UpperLeftBadge(badgeText))
struct UpperLeftBadge: ViewModifier
let badgeText: String
init(_ badgeText: String)
self.badgeText = badgeText
func body(content: Content) -> some View
content
.overlay(
ZStack
Badge(badgeText)
.padding([.top, .leading], 5),
alignment: .topLeading
)
即,单元格中的用法如下所示:
.if(condition)
$0.upperLeftBadge(badgeText)
当我更改修饰符以使用它而不使用这个 .if
修饰符并直接使用它时,问题就消失了:
extension View
func upperLeftBadge(_ badgeText: String?) -> some View
return self.modifier(UpperLeftBadge(badgeText: badgeText))
struct UpperLeftBadge: ViewModifier
let badgeText: String?
func body(content: Content) -> some View
content
.overlay(
ZStack
if let badgeText = badgeText
Badge(badgeText)
.padding([.top, .leading], 5),
alignment: .topLeading
)
【讨论】:
以上是关于LazyVGrid 列表中的单元格有时会消失的主要内容,如果未能解决你的问题,请参考以下文章
如何正确地将“单元格项目”从 SwiftUI LazyVGrid 传递给 .sheet?
如何正确地将“单元格项目”从 SwiftUI LazyVGrid 传递给 .sheet?