Home > database >  SwiftUI: Play video only if it's in the centre of the screen
SwiftUI: Play video only if it's in the centre of the screen

Time:01-31

Hi am making app which plays video only If it's in the centre of the view. I've already managed to get the position in the scroll view, but I can't combine that with playing the video.

This is my main view:

struct MainView: View {
    @State var position = 0.0
    var body: some View {
        ScrollView {
            ForEach(videos){ video in
                VideoView(player: video.player)
                    .onChange(of: position) { pos in
                        if pos > -50 && pos < 400 {
                            print("Play video")
                        }else {
                            print("Stop video")
                        }
                    }
            }
            .background(GeometryReader {
                Color.clear.preference(key: ViewOffsetKey.self, value: -$0.frame(in: .named("scroll")).origin.y)
            })
            
        }.onPreferenceChange(ViewOffsetKey.self) {
            position = $0
        }
        .coordinateSpace(name: "scroll")
        .padding()
    }
}

This is my video model:

struct VideoModel: Identifiable {
    var id = UUID()
    var number: Int
    var player: AVPlayer
}

This is video array:

let videos = [
    VideoModel(number: 1, player: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "video", ofType: "mp4")!))),
    VideoModel(number: 3, player: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "video", ofType: "mp4")!))),
    VideoModel(number: 4, player: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "video", ofType: "mp4")!))),
    VideoModel(number: 5, player: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "video", ofType: "mp4")!)))
]

And those are structures handling the video player and preference key:

struct ViewOffsetKey: PreferenceKey {
    typealias Value = CGFloat
    static var defaultValue = CGFloat.zero
    static func reduce(value: inout Value, nextValue: () -> Value) {
        value  = nextValue()
    }
}

struct VideoView: View {
    var player: AVPlayer
    var body: some View {
        AVPlayerControllerRepresented(player: player)
            .frame(height: height)
    }
}

struct AVPlayerControllerRepresented : UIViewControllerRepresentable {
    var player : AVPlayer
    
    func makeUIViewController(context: Context) -> AVPlayerViewController {
        let controller = AVPlayerViewController()
        controller.player = player
        controller.showsPlaybackControls = false
        return controller
    }
    
    func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
        
    }
}

Please help, I will be so thankful.

CodePudding user response:

First You need to make the AVPlayer a Binding for the changes in VideoView & AVPlayerControllerRepresented to take effect, then add those pieces of code accordingly

player.play() // to play
player.stop() // to stop
  •  Tags:  
  • Related