Рендеринг видео не плавный в ScrollView

У меня есть базовое представление прокрутки SwiftUI, в котором находится много видео. Когда я убираю красный цвет внутри видеоплеера, прокрутка становится очень плавной, и я могу проводить пальцем вниз и вверх так быстро, как только могу, без каких-либо сбоев. Однако, когда я добавляю красный цвет и провожу пальцем вниз, а затем вверх, просмотр прокрутки дает сбой, поскольку видео снова визуализируется. Как я могу исправить этот глюк? Кроме того, в таких приложениях, как Instagram или Twitter, видео уже отображаются сразу при их появлении, и прокрутка и возврат не приведет к их повторному рендерингу. Как я могу добиться такого поведения? Это может исправить сбой при рендеринге видео.

Скопируйте вставляемый код

import SwiftUI
import AVFoundation
import AVKit

struct allVids: Identifiable, Hashable {
    var id: String
    var video: String?
}

struct MainTabViewXX: View {
    @State var someData: [allVids] = [
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2F0FCE66A1-06F7-47CC-A38A-9A95192A2728.mp4?alt=media&token=57921e5a-e5e6-4b54-919b-39be9fbead84"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2F0FCE66A1-06F7-47CC-A38A-9A95192A2728.mp4?alt=media&token=57921e5a-e5e6-4b54-919b-39be9fbead84"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2F0FCE66A1-06F7-47CC-A38A-9A95192A2728.mp4?alt=media&token=57921e5a-e5e6-4b54-919b-39be9fbead84"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2F0FCE66A1-06F7-47CC-A38A-9A95192A2728.mp4?alt=media&token=57921e5a-e5e6-4b54-919b-39be9fbead84"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2F0FCE66A1-06F7-47CC-A38A-9A95192A2728.mp4?alt=media&token=57921e5a-e5e6-4b54-919b-39be9fbead84"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2F0A514500-F1A0-4093-98A2-2847FE46484A.mp4?alt=media&token=69afd165-1ab6-4686-9ad2-2ce485090fe1"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2FE8937043-873E-4178-A90D-C6C03684C700.mp4?alt=media&token=ddc1f616-5427-4722-a96f-ab81739b243e"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2FE8937043-873E-4178-A90D-C6C03684C700.mp4?alt=media&token=ddc1f616-5427-4722-a96f-ab81739b243e"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2FE8937043-873E-4178-A90D-C6C03684C700.mp4?alt=media&token=ddc1f616-5427-4722-a96f-ab81739b243e"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2FE8937043-873E-4178-A90D-C6C03684C700.mp4?alt=media&token=ddc1f616-5427-4722-a96f-ab81739b243e"),
                allVids(id: UUID().uuidString, video: "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/stories%2F0FCE66A1-06F7-47CC-A38A-9A95192A2728.mp4?alt=media&token=57921e5a-e5e6-4b54-919b-39be9fbead84")]
    
    var body: some View {
        ScrollView {
           LazyVStack(spacing: 1){
               ForEach(someData) { message in
                    MessageView(urlV: URL(string: message.video ?? "")!, video: message)
               }
           }
        }.ignoresSafeArea()
    }
}

struct MessageView: View {
    @State var urlV: URL
    let video: allVids
    
    var body: some View {
        VStack {
            MessageVideoPlayerX(url: urlV, viewID: video.id)
        }
    }
}

struct MessageVideoPlayerX: View {
    @State var player: AVPlayer? = nil
    let url: URL
    @State var viewID: String
    
    init(url: URL, viewID: String? = nil) {
        self.url = url
        _viewID = State(initialValue: viewID ?? UUID().uuidString)
    }
    
    var body: some View {
        VStack {
            if let vid = player {
                VidPlayer(player: vid).frame(width: 200, height: 350)
            }
            Color.red.frame(width: 200, height: 300)
        }
        .onAppear {
            if player == nil {
                player = AVPlayer(url: url)
            }
            self.player?.isMuted = true
            
            self.player?.play()
        }
        .onDisappear {
            self.player?.pause()
        }
    }
}

struct VidPlayerX : UIViewControllerRepresentable {
    var player : AVPlayer
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<VidPlayerX>) -> AVPlayerViewController {

        let controller = AVPlayerViewController()
        controller.player = player
        controller.showsPlaybackControls = false
        controller.allowsVideoFrameAnalysis = false
        controller.videoGravity = .resizeAspectFill
        return controller
    }
    
    func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<VidPlayerX>) { }
}

Обратите внимание: в вашем @State var urlV: URL не должно быть MessageView, используйте let urlV: URL и, конечно же, не используйте принудительное разворачивание ! чего-либо, например URL-адреса. Точно так же не используйте @State var viewID: String в своем MessageVideoPlayerX.

workingdog support Ukraine 08.05.2024 08:15

Спасибо @workingdogsupportUkraine, я использовал принудительное развертывание, чтобы упростить этот вопрос. Предположим, что проблема не в государстве.

Ahmed Zaidan 08.05.2024 08:39

поскольку AVPlayer является объектом, его следует инициализировать внутри makeUIViewController, что происходит только один раз, а не в иерархии представлений, которая инициализируется много раз.

malhal 08.05.2024 16:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуйте этот подход, используя let player: AVPlayer вместо того, чтобы заново создавать его в .onAppear каждый раз, когда появляется MessageVideoPlayerX.

struct MessageVideoPlayerX: View {
    let player: AVPlayer // <--- here
    let url: URL
    let viewID: String

   init(url: URL, viewID: String? = nil) {
       self.url = url
       self.viewID = viewID ?? UUID().uuidString
       self.player = AVPlayer(url: url)  // <--- here
   }

    var body: some View {
        VStack {
            VidPlayerX(player: player).frame(width: 200, height: 350) // <--- here
            Color.red.frame(width: 200, height: 350)
        }
       .onAppear {
           player.isMuted = true
           player.play()
       }
       .onDisappear {
           player.pause()
       }
   }
}

Отлично работает, спасибо. Не могли бы вы посмотреть: stackoverflow.com/questions/78447347/…

Ahmed Zaidan 08.05.2024 11:23

Другие вопросы по теме