Video in SwiftUI

Recently I have been tinkering with SwiftUI, the new UI framework from Apple

I’m enjoying the declarative approach, the ability to have real-time previews, and that all settings are save in code (bye, bye Interface Builder).

While this new framework has a lot going for it, it still doesn’t have the same depth of functionality of UIKit, that has years of development, and you may found out that some components you rely upon in UIKit are entirely non-existent in SwiftUI. But don’t despair Apple make it very easy to reuse any UIKit components by using two protocols to wrap around UIKit components:

They have very similar interfaces the main difference being what type of class they wrap around.

UIViewControllerRepresentable, as the name indicates, is used to wrap around UIViewController classes while the UIViewRepresentable wraps UIView classes.

One of the components missing in SwiftUI is a video view, so let’s see how can we use these protocols to implement it in SwiftUI.

For our video component, we are using an AVPlayerViewController so we will need to wrap it using a UIViewControllerRepresentable protocol and implement the following methods:

  • makeUIViewController() 
  • updateUIViewController()

Let’s see how we can implement those. We start by creating our video view:

public struct Video: UIViewControllerRepresentable {

  /// The URL of the video you want to display
  let videoURL: URL

Then we implement makeUIViewController():

public func makeUIViewController(context: Context) -> AVPlayerViewController {
  let videoViewController = AVPlayerViewController()
  videoViewController.player = AVPlayer(url: videoURL)
  return videoViewController

As you can see the goal of this method is to create the UIViewController we want to use and return it.

Next, we can implement the updateUIViewController() method, because at the moment we don’t allow any change to our video component after creation we can simply do this:

public func updateUIViewController(_ videoViewController: AVPlayerViewController, context: Context) {


At that’s it, our video component is ready to be used! You only need to do this:

struct VideoPlayerView: View {
  let videoURL = Bundle.main.url(forResource: "video", withExtension: "mp4")!
  var body: some View {
        Video(url: videoURL)

Build and run, and you should see something like this:

You now have a ready to use video view, as you may have noticed the video expanded to the full screen because that is the default behaviour of the AVPlayerViewController, this is not ideal for some scenarios so let’s see how can we fix this.

One of the great thing of using this representable protocols is that you inherit for free all the modifies available for the View component so you can change the code to this:

Video(url: videoURL).frame(width: nil, height: CGFloat(exactly:300), alignment: .center)

Build and run you should see this:

That was easy!

On the next post I will show you how to add some dynamic properties to the video view.

Meanwhile if you want to check the end result you can have a look on the SVEVideoUI project repository in Github.






4 responses to “Video in SwiftUI”

  1. Video in SwiftUI – Part 2 Properties – Sérgio Estêvão Avatar

    […] the previous article, we created our Video component for SwiftUI. It was working correctly, but there was not a lot of […]


  2. Video in SwiftUI – Part 3 Coordinator – Sérgio Estêvão Avatar

    […] you remember the UIViewControllerRepresentable protocol from part 1, beside the makeViewController() and createViewController() methods there is a third method in the […]


  3. Larry Anglin Avatar

    Just a quick typo, where it says: “You know a have..”, ‘Know’ should be ‘Now’.

    Liked by 1 person

    1. Sérgio Estêvão Avatar

      Thanks for the feedback just fixed the typos.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: