简体   繁体   English

SwiftUI LazyVGrid NavigationLink 返回异常 animation

[英]SwiftUI LazyVGrid NavigationLink has unusual animation on return

I have a NavigationLink within a LazyVGrid and am getting this animation on return from the details view .我在 LazyVGrid 中有一个 NavigationLink,并且在从详细信息视图返回时得到这个 animation Starting at about 3.5 seconds into that video, there is an animation I wasn't expecting.从该视频的大约 3.5 秒开始,有一个我没想到的 animation。 There are gaps introduced between the cells and I don't like the way it looks.单元之间引入了间隙,我不喜欢它的外观。

Here is the code for the screen with the LazyVGrid:下面是带有 LazyVGrid 的屏幕代码:


import Foundation
import SwiftUI
import SFSafeSymbols
import CustomModalView

struct AlbumItemsScreen: View {
    @ObservedObject var viewModel:AlbumItemsViewModel
    let gridItemLayout = [GridItem(.adaptive(minimum: 50), spacing: 20)]
    @State var object: ServerObjectModel?
    @State var enableNavLink: Bool = false
    
    var body: some View {        
        RefreshableScrollView(refreshing: $viewModel.loading) {
            LazyVGrid(columns: gridItemLayout) {
                ForEach(viewModel.objects, id: \.fileGroupUUID) { item in
                    AlbumItemsScreenCell(object: item)
                        .onTapGesture {
                            object = item
                            viewModel.showCellDetails = true
                        }

                    // Without this conditional, "spacer" cells show up in the grid.
                    if viewModel.showCellDetails, let object = object {
                        // The `NavigationLink` works here because the `MenuNavBar` contains a `NavigationView`.
                        NavigationLink(
                            destination:
                                // If I just use `item` directly in this-- oddly, it doesn't reference the same object as for `AlbumItemsScreenCell` above.
                                ObjectDetailsView(object: object),
                            isActive:
                                $viewModel.showCellDetails) {
                        }
                    } // end if
                } // end ForEach
            } // end LazyVGrid
            .padding(10)
        }
        .alert(isPresented: $viewModel.presentAlert, content: {
            let message:String = viewModel.alertMessage
            viewModel.alertMessage = nil
            return Alert(title: Text(message))
        })
        .navigationBarTitle("Album Contents")
        .navigationBarItems(trailing:
            AlbumItemsScreenNavButtons(viewModel: viewModel)
        )
        .disabled(viewModel.addNewItem)
        .modal(isPresented: $viewModel.addNewItem) {
            AddItemModal(viewModel: viewModel)
                .padding(20)
        }
        .modalStyle(DefaultModalStyle())
        .onDisappear {
            // I'm having a problem with the modal possibly being presented, the user navigating away, coming back and the modal still being present.
            // See also https://github.com/jankaltoun/CustomModalView/issues/1
            if viewModel.addNewItem == true {
                viewModel.addNewItem = false
            }
        }
    }
}

private struct AlbumItemsScreenNavButtons: View {
    @ObservedObject var viewModel:AlbumItemsViewModel
    
    var body: some View {
        HStack(spacing: 0) {
            Button(
                action: {
                    viewModel.sync()
                },
                label: {
                    SFSymbolNavBar(symbol: .goforward)
                }
            )
            
            Button(
                action: {
                    viewModel.startNewAddItem()
                },
                label: {
                    SFSymbolNavBar(symbol: .plusCircle)
                }
            )
        }
    }
}

(see also https://github.com/SyncServerII/Neebla/blob/main/Neebla/UI/Screens/Album%20Items/AlbumItemsScreen.swift ). (另请参见https://github.com/SyncServerII/Neebla/blob/main/Neebla/UI/Screens/Album%20Items/AlbumItemsScreen.swift )。

Here is the code for the details view:这是详细信息视图的代码:


import Foundation
import SwiftUI
import SFSafeSymbols

struct ObjectDetailsView: View {
    let object:ServerObjectModel
    var model:MessagesViewModel?
    @State var showComments = false
    
    init(object:ServerObjectModel) {
        self.object = object
        model = MessagesViewModel(object: object)
    }
    
    var body: some View {
        VStack {
            AnyLargeMedia(object: object)
                .onTapGesture {
                    if let _ = model {
                        showComments = true
                    }
                }
                
            Spacer()
        }
        .navigationBarItems(trailing:
            Button(
                action: {
                    showComments = true
                },
                label: {
                    SFSymbolNavBar(symbol: .message)
                }
            )
            .enabled(model != nil)
        )
        .sheet(isPresented: $showComments) {
            if let model = model {
                CommentsView(model: model)
            }
            else {
                // Should never get here. Should never have showComments == true when model is nil.
                EmptyView()
            }
        }
    }
}

(see also https://github.com/SyncServerII/Neebla/blob/main/Neebla/UI/Screens/Object%20Details/ObjectDetailsView.swift ). (另请参阅https://github.com/SyncServerII/Neebla/blob/main/Neebla/UI/Screens/Object%20Details/ObjectDetailsView.swift )。

I've tried the strategy indicated here https://developer.apple.com/forums/thread/125937 with this:我已经尝试过此处https://developer.apple.com/forums/thread/125937指示的策略:

                        NavigationLink(
                            destination:
                                // If I just use `item` directly in this-- oddly, it doesn't reference the same object as for `AlbumItemsScreenCell` above.
                                ObjectDetailsView(object: object),
                            isActive:
                                $viewModel.showCellDetails) {
                            EmptyView()
                        }
                        .frame(width: 0, height: 0)
                        .disabled(true) 

but the same effect occurs.但同样的效果发生。

Well, it helped to focus my attention on the problem by writing up this question.好吧,通过写下这个问题,它有助于将我的注意力集中在问题上。 I've come up with a solution.我想出了一个解决方案。 I took the NavigationLink out of the scrollview and LazyVGrid:我从滚动视图和 LazyVGrid 中取出了 NavigationLink:


import Foundation
import SwiftUI
import SFSafeSymbols
import CustomModalView

struct AlbumItemsScreen: View {
    @ObservedObject var viewModel:AlbumItemsViewModel
    let gridItemLayout = [GridItem(.adaptive(minimum: 50), spacing: 20)]
    @State var object: ServerObjectModel?
    
    var body: some View {
        VStack {
            RefreshableScrollView(refreshing: $viewModel.loading) {
                LazyVGrid(columns: gridItemLayout) {
                    ForEach(viewModel.objects, id: \.fileGroupUUID) { item in
                        AlbumItemsScreenCell(object: item)
                            .onTapGesture {
                                object = item
                                viewModel.showCellDetails = true
                            }
                    } // end ForEach
                } // end LazyVGrid
                .padding(10)
            }
            
            if let object = object {
                // The `NavigationLink` works here because the `MenuNavBar` contains a `NavigationView`.
                NavigationLink(
                    destination:
                        ObjectDetailsView(object: object),
                    isActive:
                        $viewModel.showCellDetails) {
                    EmptyView()
                }
                .frame(width: 0, height: 0)
                .disabled(true)
            } // end if
        }
        .alert(isPresented: $viewModel.presentAlert, content: {
            let message:String = viewModel.alertMessage
            viewModel.alertMessage = nil
            return Alert(title: Text(message))
        })
        .navigationBarTitle("Album Contents")
        .navigationBarItems(trailing:
            AlbumItemsScreenNavButtons(viewModel: viewModel)
        )
        .disabled(viewModel.addNewItem)
        .modal(isPresented: $viewModel.addNewItem) {
            AddItemModal(viewModel: viewModel)
                .padding(20)
        }
        .modalStyle(DefaultModalStyle())
        .onDisappear {
            // I'm having a problem with the modal possibly being presented, the user navigating away, coming back and the modal still being present.
            // See also https://github.com/jankaltoun/CustomModalView/issues/1
            if viewModel.addNewItem == true {
                viewModel.addNewItem = false
            }
        }
    }
}

private struct AlbumItemsScreenNavButtons: View {
    @ObservedObject var viewModel:AlbumItemsViewModel
    
    var body: some View {
        HStack(spacing: 0) {
            Button(
                action: {
                    viewModel.sync()
                },
                label: {
                    SFSymbolNavBar(symbol: .goforward)
                }
            )
            
            Button(
                action: {
                    viewModel.startNewAddItem()
                },
                label: {
                    SFSymbolNavBar(symbol: .plusCircle)
                }
            )
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM