1

I have followed two tutorials on UIViewRepresentable and thought the following would work, yet it didn't and I think my situation is more complex than in the tutorials.

Hello, I am trying to turn this code

 import SpriteKit
 import AVFoundation

class ViewController: NSViewController {
    
    @IBOutlet var skView: SKView!
    var videoPlayer: AVPlayer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let view = self.skView {
            // Load the SKScene from 'backgroundScene.sks'
            guard let scene = SKScene(fileNamed: "backgroundScene") else {
                print ("Could not create a background scene")
                return
            }
            // Set the scale mode to scale to fit the window
            scene.scaleMode = .aspectFill
            // Present the scene
            view.presentScene(scene)
            
            // Add the video node
            guard let alphaMovieURL = Bundle.main.url(forResource: "camera_city_animated", withExtension: "mov") else {
                print("Failed to overlay alpha movie on the background")
                return
            }
            videoPlayer = AVPlayer(url: alphaMovieURL)
            let video = SKVideoNode(avPlayer: videoPlayer)
            video.size = CGSize(width: view.frame.width, height: view.frame.height)
            print( "Video size is %f x %f", video.size.width, video.size.height)
            scene.addChild(video)
            
            // Play video
            videoPlayer.play()
            
            videoPlayer?.actionAtItemEnd = .none

            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(playerItemDidReachEnd(notification:)),
                                                   name: .AVPlayerItemDidPlayToEndTime,
                                                   object: videoPlayer?.currentItem)

            
        }
    }
    @objc func playerItemDidReachEnd(notification: Notification) {
        if let playerItem = notification.object as? AVPlayerItem {
            playerItem.seek(to: CMTime.zero, completionHandler: nil)
        }
    }
}

Into a SwiftUI View by placing it inside the func makeUIView(context: Context) -> UITextView {} of my struct TransparentVideoLoop: UIViewRepresentable {} struct.

What am I missing?

Full code:

struct TransparentVideoLoop: UIViewRepresentable {
    func makeUIView(context: Context) -> UITextView {
        @IBOutlet var skView: SKView!
        var videoPlayer: AVPlayer!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            if let view = self.skView {
                // Load the SKScene from 'backgroundScene.sks'
                guard let scene = SKScene(fileNamed: "backgroundScene") else {
                    print ("Could not create a background scene")
                    return
                }
                // Set the scale mode to scale to fit the window
                scene.scaleMode = .aspectFill
                // Present the scene
                view.presentScene(scene)
                
                // Add the video node
                guard let alphaMovieURL = Bundle.main.url(forResource: "camera_city_animated", withExtension: "mov") else {
                    print("Failed to overlay alpha movie on the background")
                    return
                }
                videoPlayer = AVPlayer(url: alphaMovieURL)
                let video = SKVideoNode(avPlayer: videoPlayer)
                video.size = CGSize(width: view.frame.width, height: view.frame.height)
                print( "Video size is %f x %f", video.size.width, video.size.height)
                scene.addChild(video)
                
                // Play video
                videoPlayer.play()
                
                videoPlayer?.actionAtItemEnd = .none

                NotificationCenter.default.addObserver(self,
                                                       selector: #selector(playerItemDidReachEnd(notification:)),
                                                       name: .AVPlayerItemDidPlayToEndTime,
                                                       object: videoPlayer?.currentItem)

                
            }
        }
        @objc func playerItemDidReachEnd(notification: Notification) {
            if let playerItem = notification.object as? AVPlayerItem {
                playerItem.seek(to: CMTime.zero, completionHandler: nil)
            }
        }
    }
    

    func updateUIView(_ uiView: UITextView, context: Context) {
       
    }
}

I have to return the view, but this is more complex than in the tutorials.

sivafe9540
  • 23
  • 7
  • 1
    Use instead `UIViewControllerRepresentable` and and just wrap entire `ViewController` in `makeUIViewController`. – Asperi Jul 31 '22 at 06:04

1 Answers1

0

Use UIViewControllerRepresentable instead, e.g.

import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {
    @Binding var selectedImage: UIImage?
    @Environment(\.presentationMode) var presentationMode

    func makeCoordinator() -> ImagePicker.Coordinator {
        Coordinator()
    }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}

    func makeUIViewController(context: Context) -> some UIViewController {
        context.coordinator.imagePicker
    }

    final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        
        lazy var imagePicker: UIImagePickerController = {
            let imagePickerController = UIImagePickerController()
            imagePickerController.sourceType = .photoLibrary
            imagePickerController.delegate = self
            return imagePickerController
        }()

        var imageSelected: ((UIImage) -> Void)?

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
            DispatchQueue.main.async {
                if let selectedImage = (info[.editedImage] ?? info[.originalImage]) as? UIImage {
                    imageSelected?(selectedImage)
                }
                //self.parent.presentationMode.wrappedValue.dismiss()
            }
        }
    }
}

Note this is inspired by ImagePicker.swift from an Apple sample but the developer got the Coordinator wrong so I have corrected that. It also needs the update func fixed.

malhal
  • 26,330
  • 7
  • 115
  • 133