0

I am writing an app for tvOS that launches videos from URL's into an AVPlayerView, which is not nested in another View. The trouble is, the user had no idea anything was going on while loading was occurring, so I wanted to add an activity indicator in the center of the screen.

Getting the screen center is not straightforward while a video is loading, however, because the view's bounds are set to (0, 0, 0, 0) while the video is loading, so setting the subview's center = view.center doesn't work (it will just add my subviews in the upper left corner of the screen).

How can I add a subview into the center of the screen, when the frame is set to (0, 0, 0, 0)?

D. Pratt
  • 444
  • 8
  • 15

1 Answers1

0

Luckily, I was able to find the answer on my own. UIScreen works just as well with tvOS as it would on an iOS device. My complete solution is below, hope it helps save someone some time. I am including my observers that trigger the end as well.

The class that I used to handle the activity

class VideoLoadingActivityIndicator {

var loadingActivityIndicator:UIActivityIndicatorView!
var loadingLabel: UILabel!

func beginLoadingActivity(viewController:UIViewController)
{
    loadingActivityIndicator = UIActivityIndicatorView(frame:CGRect(x: 500, y: 500, width: 500, height: 500)) as UIActivityIndicatorView
    loadingActivityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
    loadingActivityIndicator.sizeToFit()
    loadingActivityIndicator.color = UIColor.white

This is the part where you use UIScreen to get the bounds

    let screenBounds = UIScreen.main.bounds
    let centerX = screenBounds.size.width / 2
    let centerY = screenBounds.size.height / 2
    let loadingLabelCenterY = centerY + 48
    let activityIndicatorCenter = CGPoint(x: centerX, y: centerY)

    loadingActivityIndicator.center = activityIndicatorCenter

I added a label to add some clarity

    loadingLabel = UILabel(frame: CGRect(x: centerX, y: loadingLabelCenterY, width: 600, height: 100))
    loadingLabel.font = UIFont(name: "Helvetica", size: 30)
    loadingLabel.text = "Loading Video"
    loadingLabel.numberOfLines = 1
    loadingLabel.sizeToFit()
    loadingLabel.textAlignment = .center
    // reset frame so it is centered in screen
    let labelWidth = loadingLabel.frame.width
    let labelHeight = loadingLabel.frame.height
    let loadingLabelCenterX = centerX - (labelWidth / 2)
    loadingLabel.frame = CGRect(x: loadingLabelCenterX, y: loadingLabelCenterY, width: labelWidth, height: labelHeight)
    loadingLabel.textColor = UIColor.white

    // Add indicator and label to subview
    viewController.view.addSubview(loadingActivityIndicator)
    viewController.view.addSubview(loadingLabel)

    self.loadingActivityIndicator.startAnimating()
}

func endLoadingActivity(viewController:UIViewController)-> Void
{
    loadingActivityIndicator.removeFromSuperview()
    loadingLabel.removeFromSuperview()
}

And then in the AVPlayerViewController that you want to add some the loading activity to...

First create the activity indicator object:

let indicator = VideoLoadingActivityIndicator()

Create your asset, and playerItem (I set some player item keys)

let asset = AVAsset(url: runFile)
let assetKeys = [
        "playable",
        "hasProtectedContent"
    ]
let playerItem = AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: assetKeys)

start the activity indicator animations

indicator.beginLoadingActivity(viewController: self, color: .white)

Add notification to player and start playback

playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
player = AVPlayer(playerItem: playerItem)
    player?.play()

Finally, handle the observer:

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "status" && player?.status == AVPlayerStatus.readyToPlay {
        indicator.endLoadingActivity(viewController: self)
    }
}

Hope this helps someone else who runs into some of the same issues I did.

D. Pratt
  • 444
  • 8
  • 15