.onAppear не вызывается для элементов моего списка после использования элемента управления обновлением ⇐ IOS
-
Гость
.onAppear не вызывается для элементов моего списка после использования элемента управления обновлением
Я пытаюсь реализовать нумерацию страниц в своей lazyvgrid, а также элемент управления обновлением. изначально, когда страница загружается, разбивка на страницы работает - для каждой ячейки вызывается onAppear. но когда я тяну, чтобы обновить, onAppear не вызывается для ячеек, поэтому загружается только первая страница:
struct AlbumListView: Просмотр { @Environment(\.horizontalSizeClass) var HorizontalSize @StateObject var viewModel: LibraryViewModel @EnvironmentObject var координатор: Координатор База данных @EnvironmentObject var: База данных @EnvironmentObject var accountHolder: AccountHolder funcgridItems(ширина: Double) -> ([GridItem], Двойной) { let count = Int((ширина / 200,0).rounded()) let item = GridItem(.flexible(), интервал: 8, выравнивание: .top) let itemWidth: Double = (ширина-(8*(Double(count)+1)))/Double(count) return (Массив (повторяющийся: элемент, количество: количество), itemWidth) } var body: some View { если UIDevice.current.userInterfaceIdiom == .pad { GeometryReader { геометрия в ПрокруткаView { let (gridItems, ширина) = GridItems (ширина: геометрия.размер.ширина) LazyVGrid (столбцы: GridItems, интервал: 8) { ForEach(viewModel.albums) {альбом в Кнопка { viewModel.albumTapped(albumId: album.id, координатор: координатор) } этикетка: { AlbumGridCell (альбом: Альбом (albumListResponse: альбом), ширина: ширина) } .onAppear { viewModel.albumAppeared(альбом: альбом) } } } .padding(8) } .simultanGesture(DragGesture().onChanged({значение в сАнимацией { MediaControlBarMinimized.shared.isCompact = true } })) .обновляемый { делать { попробуйте дождаться viewModel.loadContent(force: true) } ловить { печать (ошибка) } } .searchable(текст: $viewModel.searchText, приглашение: «Поиск по альбомам») .scrollDismissesKeyboard(.немедленно) .navigationBarTitleDisplayMode(.inline) .navigationTitle(viewModel.viewType.rawValue.capitalized) .toolbar { ToolbarTitleMenu { Picker("Picker", выбор: $viewModel.viewType) { ForEach(LibraryViewType.allCases, id: \.self) {элемент в Текст(item.rawValue.заглавные буквы) } } } ToolbarItem (размещение: .navigationBarLeading) { Кнопка { viewModel.goToLogin(координатор: координатор) } этикетка: { Изображение(systemName: "person.circle").imageScale(.large) } } ToolbarItem (размещение: .navigationBarTrailing) { Кнопка { viewModel.shuffle() } этикетка: { Изображение(systemName: "shuffle").imageScale(.large) } } } } } еще { List(viewModel.albums) {альбом в Кнопка { viewModel.albumTapped(albumId: album.id, координатор: координатор) } этикетка: { AlbumCell(альбом: Альбом(albumListResponse: альбом)) } .listRowSeparator(.скрытый) .onAppear { viewModel.albumAppeared(альбом: альбом) } } .simultanGesture(DragGesture().onChanged({значение в сАнимацией { MediaControlBarMinimized.shared.isCompact = true } })) .обновляемый { делать { попробуйте дождаться viewModel.loadContent(force: true) } ловить { печать (ошибка) } } .listStyle(.plain) .searchable(текст: $viewModel.searchText, приглашение: «Поиск по альбомам») .scrollDismissesKeyboard(.немедленно) .navigationBarTitleDisplayMode(.inline) .navigationTitle(viewModel.viewType.rawValue.capitalized) .toolbar { ToolbarTitleMenu { Picker("Picker", выбор: $viewModel.viewType) { ForEach(LibraryViewType.allCases, id: \.self) {элемент в Текст(item.rawValue.заглавные буквы) } } } ToolbarItem (размещение: .navigationBarLeading) { Кнопка { viewModel.goToLogin(координатор: координатор) } этикетка: { Изображение(systemName: "person.circle").imageScale(.large) } } ToolbarItem (размещение: .navigationBarTrailing) { Кнопка { viewModel.shuffle() } этикетка: { Изображение(systemName: "shuffle").imageScale(.large) } } } } } } моя модель представления:
класс LibraryViewModel: ObservableObject { @Published var searchText: String @Published var viewType = Database.shared.libraryViewType вар альбомPage = 0 вар player = AudioManager.shared база данных вар = Database.shared вар альбомы: [GetAlbumListResponse.Album] { если searchText.isEmpty { вернуть базу данных.albumList ?? [] } еще { вернуть базу данных.albumList?.filter { $0.title.localizedCaseInsensivityContains(searchText) || $0.artist.localizedCaseInsensivityContains(searchText) } ?? [] } } вар художников: [GetIndexesResponse.Artist] { если searchText.isEmpty { вернуть базу данных.artistList ?? [] } еще { вернуть базу данных.artistList?.filter { $0.name.localizedCaseInsensivityContains(searchText) } ?? [] } } в этом() { поискТекст = "" Задача { делать { попробуйте дождаться loadContent (force: true) } ловить { печать (ошибка) } } NotificationCenter.default.addObserver(self, селектор: #selector(refresh), имя: Notification.Name("login"), объект: ноль) } func loadContent(force: Bool = false) асинхронный бросок { переключить viewType { чехол .альбомы: если база данных.albumList == ноль || сила { self.albumPage = 0 попробуйте дождаться getAlbumList() } чехол .художники: попробуй дождись getArtists() } } func getAlbumList() асинхронно выдает { let ответ = попробуйте подождать SubsonicClient.shared.getAlbumList (страница: albumPage) DispatchQueue.main.async { если self.albumPage == 0 { self.database.albumList = response.subsonicResponse.albumList.album } еще { self.database.albumList?.append(contentsOf: response.subsonicResponse.albumList.album) } self.albumPage += 1 print("Страница: \(self.albumPage), количество альбомов: \(self.albums.count)") } } func getArtists() асинхронный бросок { пусть ответ = попробуйте дождаться SubsonicClient.shared.getIndexes() пусть художники: [GetIndexesResponse.Artist] = response.subsonicResponse.indexes.index.flatMap { индекс в вернуть index.artist } DispatchQueue.main.async { self.database.artistList = художники } } func albumAppeared(album: GetAlbumListResponse.Album) { если альбом == self.albums.last { Задача { делать { попробуйте подождать self.getAlbumList() } ловить { печать (ошибка) } } } } func albumTapped(albumId: String, координатор: Координатор) { координатор.albumTapped(albumId: albumId, ScrollToSong: ноль) } @objc func обновить() { Задача { делать { попробуйте дождаться loadContent (force: true) } ловить { печать (ошибка) } } } функция перетасовки() { Задача { let ответ = попробуйте подождать SubsonicClient.shared.getRandomSongs() let song = response.subsonicResponse.randomSongs.song.compactMap { вернуть песню (randomSong: $0) } DispatchQueue.main.async { self.player.play(песни:песни, индекс: 0) } } } func goToLogin(координатор: Координатор) { координатор.goToLogin() } } Database.shared — это наблюдаемый объект в корне приложения, поэтому @Published здесь не требуется, представление перерисовывается при его изменении Я предполагаю, что это как-то связано с LazyVGrid, поскольку этого не происходит при использовании списка (в моем макете iPhone)
Я пытаюсь реализовать нумерацию страниц в своей lazyvgrid, а также элемент управления обновлением. изначально, когда страница загружается, разбивка на страницы работает - для каждой ячейки вызывается onAppear. но когда я тяну, чтобы обновить, onAppear не вызывается для ячеек, поэтому загружается только первая страница:
struct AlbumListView: Просмотр { @Environment(\.horizontalSizeClass) var HorizontalSize @StateObject var viewModel: LibraryViewModel @EnvironmentObject var координатор: Координатор База данных @EnvironmentObject var: База данных @EnvironmentObject var accountHolder: AccountHolder funcgridItems(ширина: Double) -> ([GridItem], Двойной) { let count = Int((ширина / 200,0).rounded()) let item = GridItem(.flexible(), интервал: 8, выравнивание: .top) let itemWidth: Double = (ширина-(8*(Double(count)+1)))/Double(count) return (Массив (повторяющийся: элемент, количество: количество), itemWidth) } var body: some View { если UIDevice.current.userInterfaceIdiom == .pad { GeometryReader { геометрия в ПрокруткаView { let (gridItems, ширина) = GridItems (ширина: геометрия.размер.ширина) LazyVGrid (столбцы: GridItems, интервал: 8) { ForEach(viewModel.albums) {альбом в Кнопка { viewModel.albumTapped(albumId: album.id, координатор: координатор) } этикетка: { AlbumGridCell (альбом: Альбом (albumListResponse: альбом), ширина: ширина) } .onAppear { viewModel.albumAppeared(альбом: альбом) } } } .padding(8) } .simultanGesture(DragGesture().onChanged({значение в сАнимацией { MediaControlBarMinimized.shared.isCompact = true } })) .обновляемый { делать { попробуйте дождаться viewModel.loadContent(force: true) } ловить { печать (ошибка) } } .searchable(текст: $viewModel.searchText, приглашение: «Поиск по альбомам») .scrollDismissesKeyboard(.немедленно) .navigationBarTitleDisplayMode(.inline) .navigationTitle(viewModel.viewType.rawValue.capitalized) .toolbar { ToolbarTitleMenu { Picker("Picker", выбор: $viewModel.viewType) { ForEach(LibraryViewType.allCases, id: \.self) {элемент в Текст(item.rawValue.заглавные буквы) } } } ToolbarItem (размещение: .navigationBarLeading) { Кнопка { viewModel.goToLogin(координатор: координатор) } этикетка: { Изображение(systemName: "person.circle").imageScale(.large) } } ToolbarItem (размещение: .navigationBarTrailing) { Кнопка { viewModel.shuffle() } этикетка: { Изображение(systemName: "shuffle").imageScale(.large) } } } } } еще { List(viewModel.albums) {альбом в Кнопка { viewModel.albumTapped(albumId: album.id, координатор: координатор) } этикетка: { AlbumCell(альбом: Альбом(albumListResponse: альбом)) } .listRowSeparator(.скрытый) .onAppear { viewModel.albumAppeared(альбом: альбом) } } .simultanGesture(DragGesture().onChanged({значение в сАнимацией { MediaControlBarMinimized.shared.isCompact = true } })) .обновляемый { делать { попробуйте дождаться viewModel.loadContent(force: true) } ловить { печать (ошибка) } } .listStyle(.plain) .searchable(текст: $viewModel.searchText, приглашение: «Поиск по альбомам») .scrollDismissesKeyboard(.немедленно) .navigationBarTitleDisplayMode(.inline) .navigationTitle(viewModel.viewType.rawValue.capitalized) .toolbar { ToolbarTitleMenu { Picker("Picker", выбор: $viewModel.viewType) { ForEach(LibraryViewType.allCases, id: \.self) {элемент в Текст(item.rawValue.заглавные буквы) } } } ToolbarItem (размещение: .navigationBarLeading) { Кнопка { viewModel.goToLogin(координатор: координатор) } этикетка: { Изображение(systemName: "person.circle").imageScale(.large) } } ToolbarItem (размещение: .navigationBarTrailing) { Кнопка { viewModel.shuffle() } этикетка: { Изображение(systemName: "shuffle").imageScale(.large) } } } } } } моя модель представления:
класс LibraryViewModel: ObservableObject { @Published var searchText: String @Published var viewType = Database.shared.libraryViewType вар альбомPage = 0 вар player = AudioManager.shared база данных вар = Database.shared вар альбомы: [GetAlbumListResponse.Album] { если searchText.isEmpty { вернуть базу данных.albumList ?? [] } еще { вернуть базу данных.albumList?.filter { $0.title.localizedCaseInsensivityContains(searchText) || $0.artist.localizedCaseInsensivityContains(searchText) } ?? [] } } вар художников: [GetIndexesResponse.Artist] { если searchText.isEmpty { вернуть базу данных.artistList ?? [] } еще { вернуть базу данных.artistList?.filter { $0.name.localizedCaseInsensivityContains(searchText) } ?? [] } } в этом() { поискТекст = "" Задача { делать { попробуйте дождаться loadContent (force: true) } ловить { печать (ошибка) } } NotificationCenter.default.addObserver(self, селектор: #selector(refresh), имя: Notification.Name("login"), объект: ноль) } func loadContent(force: Bool = false) асинхронный бросок { переключить viewType { чехол .альбомы: если база данных.albumList == ноль || сила { self.albumPage = 0 попробуйте дождаться getAlbumList() } чехол .художники: попробуй дождись getArtists() } } func getAlbumList() асинхронно выдает { let ответ = попробуйте подождать SubsonicClient.shared.getAlbumList (страница: albumPage) DispatchQueue.main.async { если self.albumPage == 0 { self.database.albumList = response.subsonicResponse.albumList.album } еще { self.database.albumList?.append(contentsOf: response.subsonicResponse.albumList.album) } self.albumPage += 1 print("Страница: \(self.albumPage), количество альбомов: \(self.albums.count)") } } func getArtists() асинхронный бросок { пусть ответ = попробуйте дождаться SubsonicClient.shared.getIndexes() пусть художники: [GetIndexesResponse.Artist] = response.subsonicResponse.indexes.index.flatMap { индекс в вернуть index.artist } DispatchQueue.main.async { self.database.artistList = художники } } func albumAppeared(album: GetAlbumListResponse.Album) { если альбом == self.albums.last { Задача { делать { попробуйте подождать self.getAlbumList() } ловить { печать (ошибка) } } } } func albumTapped(albumId: String, координатор: Координатор) { координатор.albumTapped(albumId: albumId, ScrollToSong: ноль) } @objc func обновить() { Задача { делать { попробуйте дождаться loadContent (force: true) } ловить { печать (ошибка) } } } функция перетасовки() { Задача { let ответ = попробуйте подождать SubsonicClient.shared.getRandomSongs() let song = response.subsonicResponse.randomSongs.song.compactMap { вернуть песню (randomSong: $0) } DispatchQueue.main.async { self.player.play(песни:песни, индекс: 0) } } } func goToLogin(координатор: Координатор) { координатор.goToLogin() } } Database.shared — это наблюдаемый объект в корне приложения, поэтому @Published здесь не требуется, представление перерисовывается при его изменении Я предполагаю, что это как-то связано с LazyVGrid, поскольку этого не происходит при использовании списка (в моем макете iPhone)
Мобильная версия