【问题标题】:Cell in List with LazyVGrid Disappears sometimesLazyVGrid 列表中的单元格有时会消失
【发布时间】: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://stackoverflow.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 ------

嗯,这个假设是错误的。我现在更清楚地了解了问题的结构。但仍然没有修复。

点击其中一个AlbumItemsScreenCells 导航到详细信息屏幕(我已添加到上面的代码中以显示这一点)。在详细信息屏幕中,用户操作可能会导致评论计数被重置,这会发送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://stackoverflow.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。一旦您向我们展示了一个可重现的最小示例,我们就会了解更多。

标签: ios swift swiftui ios15


【解决方案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
            )
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-02
    相关资源
    最近更新 更多