#ios #swift #swiftui #swiftui-navigationlink #lazyvgrid
#iOS #swift #swiftui #swiftui-navigationlink #lazyvgrid
Вопрос:
У меня есть NavigationLink в LazyVGrid, и я получаю эту анимацию при возврате из представления сведений. Начиная примерно с 3,5 секунды этого видео, появляется анимация, которую я не ожидал. Между ячейками есть пробелы, и мне не нравится, как это выглядит.
Вот код для экрана с 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)
}
)
}
}
}
(смотрите также https://github.com/SyncServerII/Neebla/blob/main/Neebla/UI/Screens/Album Items/AlbumItemsScreen.swift).
Вот код для просмотра сведений:
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()
}
}
}
}
(смотрите также https://github.com/SyncServerII/Neebla/blob/main/Neebla/UI/Screens/Object Details/ObjectDetailsView.swift).
Я попробовал стратегию, указанную здесь 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)
но происходит тот же эффект.
Ответ №1:
Что ж, это помогло мне сосредоточить мое внимание на проблеме, написав этот вопрос. Я придумал решение. Я убрал навигационную ссылку из scrollview и 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?
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)
}
)
}
}
}