Brian Coleman

  • Home
  • ABOUT
  • SERVICES
  • PORTFOLIO
  • BLOG
  • Contact

tvOS Tutorial: Make a Video App in Swift

Finally Apple is allowing developers the ability to make our own Apple TV apps using the new tvOS SDK. tvOS is just about the same as developing for iOS but with a couple restrictions. No web views are allowed, tvOS does not contain all of the UI objects that are in iOS but it does have most of them, like buttons, alert views, table views and collection views which are probably the most common objects found in Apple TV apps currently. The other restriction is you can only use third-party frameworks that are built specifically for tvOS, you cannot reuse the same frameworks or libraries you use in your iOS or Watch OS apps.

In this tutorial we are going to build the most common type of tvOS app that is currently on the Apple TV platform, a video app. We’ll try to recreate a Netflix style layout and look at the classes and objects needed to make browsing and viewing TV shows and movies.

Project Setup

  1. Create a new project, File > New > Project
  2. Choose Application under tvOS and select “Single View Application”
    Screen Shot 2015-10-10 at 12.31.05 PM

  3. Name the Product “Video App”, and we’re going to develop it in Swift
    Screen Shot 2015-10-10 at 12.34.17 PM

Setting up the Menu

The main menu for most Apple TV apps is a tab bar controller, except for tvOS apps it’s at the top of the screen instead of the bottom like iOS apps. This menu will let the user select between the sections of the app, i.e. Movies or TV Shows.

  1. Click “Main.storyboard” from the project navigator.
  2. From the UI objects library in the bottom right of Xcode, find “Tab Bar Controller” and drag it onto the Storyboard. Use the pinch gesture on your trackpad to zoom out so you can see everything in the Storyboard.
    Screen Shot 2015-10-10 at 12.39.30 PM

  3. Select the Item 2 View Controller and name it “TV” and change the “Item 2” bar item to “TV”
    Screen Shot 2015-10-10 at 12.43.34 PM

  4. Do the same for the Item 1 Scene but change that to “Movies”
  5. Run the program and you’ll see that we have a standard tab bar with both Movies and TV. You can use your arrow keys to switch back and forth between view controllers.
    Screen Shot 2015-10-10 at 12.44.06 PM

Designing the Featured Movies Layout

Our layout is going to include one top row with the main featured movies or shows then a few rows after it which are individual movies and shows that the user can browse through, just like Netflix.

The secret to creating a tvOS app similar to the ones on the Apple TV now is to put all of your objects into a scroll view. As the user moves the focus down the page the scroll view will automatically move up or down so the user can see objects that are outside of the current visible area.

  1. Starting with the Movies Scene selected, uncheck “Under Top Bars” and “Under Bottom Bars” from the Attributes Inspector on the right. This will allow the Menu to hide smoothly when the user is at the top of the screen.
    Screen Shot 2015-10-10 at 12.48.44 PM

  2. Click on the view so we can customize the layout for our scrolling movie lists.
  3. From the UI objects library drag out a scroll view and make it the entire size of the view controller 1920 x 940.
    Screen Shot 2015-10-10 at 12.51.33 PM

  4. Next drag a UICollectionView from the UI objects library and place it at the top of the screen. This will be our main featured area. It’s size should be 1920×400.
    Screen Shot 2015-10-10 at 12.55.53 PM

  5. Set the Cell Size to 640 x 480 so we can fit 3 on the screen.
  6. Add your featured assets to the project. Right click on the Project Navigator and select “Add Files to …”, select the images you want to store locally.
  7. Back to the Storyboard, from the UI objects library drag a UIImageView into the Collection View Cell, it should be the entire width and height of the cell.
    Screen Shot 2015-10-12 at 11.38.14 AM

Custom Featured Collection View Cell

We need to create a custom collection view cell so we can tailor the layout of the cell to exactly how the design looks. We’ll call it FeaturedCollectionViewCell. Start with the large featured collection view cells.

  1. Right click in the Project Navigator, select “New File”, choose “tvOS > Source > Swift File”.
    Screen Shot 2015-10-10 at 1.44.01 PM

  2. Enter in the name of the custom class FeaturedCollectionViewCell and click “Create”.
    Screen Shot 2015-10-10 at 1.44.13 PM

Below is the code for the featured collection view class, it only contains 1 object, an UIImageView.

import UIKit

class FeaturedCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak var featuredImage: UIImageView!
    
    override init(frame: CGRect)
    {
        super.init(frame: frame)
        self.commonInit()
    }
    
    required init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)
    }
    
    private func commonInit()
    {
        // Initialization code
        
        self.layoutIfNeeded()
        self.layoutSubviews()
        self.setNeedsDisplay()
    }
    
    override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
        if (self.focused)
        {
            self.featuredImage.adjustsImageWhenAncestorFocused = true
        }
        else
        {
            self.featuredImage.adjustsImageWhenAncestorFocused = false
        }
    }
    
    override func layoutSubviews()
    {
        super.layoutSubviews()
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
    }
    
}

You’ll notice a new method you’ve never seen before:

override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
        if (self.focused)
        {
            self.featuredImage.adjustsImageWhenAncestorFocused = true
        }
        else
        {
            self.featuredImage.adjustsImageWhenAncestorFocused = false
        }
    }

Since tvOS doesn’t have touch capability like iOS or Watch OS this method tells the cell what to do when it is in focus. The adjustsImageWhenAncestorFocused property for the UIImageView will make the image expand and popout when it’s in focus for the user. This is the most common UI indicator for the user when browsing through the content.

Hook up the Featured Cell

Now that we have the custom class, we need to implement the UI objects for it within the Storyboard.

  1. Click “Main.storyboard” from the project navigator.
  2. Click the Cell under Collection View 1 and inside the Attributes Inspector change the Identifier to “FeaturedCell”. This will be our re-useable identifier when creating the cells.
    Screen Shot 2015-10-10 at 1.49.10 PM

  3. Enter the custom class “FeaturedCollectionViewCell” with the object so you can hookup the IBOutlet for the UIImageView we defined earlier.
    Screen Shot 2015-10-10 at 1.49.26 PM

  4. From the UI objects library in the bottom right of Xcode, find “Image View” and drag it onto the collection view cell. Then hookup the IBOutlet by dragging the featuredImage outlet to the FeaturedCell.
    Screen Shot 2015-10-10 at 1.49.39 PM

Movies View Controller

  1. Make a new Swift file for our Movies View Controller. Right Click on the Project Navigator and select “New File”, choose “tvOS > Source > Swift File”. Name it “MoviesViewController” and click the “Create” button.
    Screen Shot 2015-10-10 at 1.44.01 PM

  2. Enter the following code, this is everything required to get the scroll view and collection view to work with the images we have within the project.
    import Foundation
    import UIKit
    
    class MoviesViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UIScrollViewDelegate {
        
        @IBOutlet var scrollView : UIScrollView!
        @IBOutlet var collectionView1 : UICollectionView!
        let reuseIdentifierFeatured = "FeaturedCell"
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        override func viewDidLayoutSubviews() {
            self.scrollView!.contentSize = CGSizeMake(1920, 2200)
        }
    
        // Collection View Methods
        
        func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
            return 50
        }
        
        func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
            return 50
        }
        
        func collectionView(collectionView: UICollectionView,
            layout collectionViewLayout: UICollectionViewLayout,
            insetForSectionAtIndex section: Int) -> UIEdgeInsets {
                return UIEdgeInsets(top: 0.0, left: 50.0, bottom: 0.0, right: 50.0)
        }
        
        func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
            return 1
        }
        
        func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
        {
            if (collectionView == self.collectionView1)
            {
                return 8
            }
            
            return 0
        }
        
        func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
            
            if (collectionView == self.collectionView1)
            {
                let cell : FeaturedCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(self.reuseIdentifierFeatured, forIndexPath: indexPath) as! FeaturedCollectionViewCell
                
                let  imageFilename = "feature-\(indexPath.row).jpg"
                cell.featuredImage.image = UIImage(named: imageFilename)
                
                return cell
            }
            
            return UICollectionViewCell()
        }
        
    }
    

    Note: As of Beta3 the scrollView contentSize should be entered within the viewDidLayoutSubviews() method since the view size is not yet set when viewDidLoad() is called

Hook up the Outlets

All of the code has been written in the Movie View Controller class, so we just need to hookup the outlet and delegates for the scroll view and collection view.

  1. Click “Main.storyboard” from the project navigator.
  2. Define the custom class for the Movies view controller.
    Screen Shot 2015-10-12 at 12.15.29 PM

  3. Click the scroll view and drag the outlet to the Movies
    Screen Shot 2015-10-12 at 12.16.39 PM

  4. Click the Collection View and drag the delegates and outlet to the Movies view controller so we can control it within the MoviesViewController.swift file.
    Screen Shot 2015-10-12 at 12.18.16 PM

Run It

If everything is linked up correctly and the code above all entered you should see the first collection view on the screen with the images displayed.

Screen Shot 2015-10-10 at 2.04.22 PM

Scrolling Movies

If you would like to have categories that the user can browse through, you can make them by adding more collection views below the featured one that we just created. Each collection view will be unique with it’s own set of data.

Download the entire project at the end of this tutorial to see how I did it.

Screen Shot 2015-10-12 at 12.27.45 PM

Playing Video

The last feature we need to make is allowing the user to watch video once one of the movies or TV shows has been selected.

  1. Make a new Swift file for our Player View Controller. Right Click on the Project Navigator and select “New File”, choose “tvOS > Source > Swift File”. Name it “PlayerViewController” and click the “Create” button.
  2. Add the following code to it:
    import Foundation
    import UIKit
    import AVKit
    
    class PlayerViewController: AVPlayerViewController, AVPlayerViewControllerDelegate {
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        func playVideo() {
            
            player = AVPlayer(URL: NSURL(string: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")!)
            player?.play()
        }
        
    }
    
  3. Add the following collection view method to the the MoviesViewController.swift so when a cell is selected it’ll open up the PlayerViewController:
    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        let playerVC = PlayerViewController()
        playerVC.playVideo()
        [self.presentViewController(playerVC, animated: true, completion: nil)]
    }
    
  4. Click “Main.storyboard” from the project navigator.
  5. From the UI objects library in the bottom right of Xcode, find “AVKit Player View Controller” and drag it onto the Storyboard.
  6. Change the custom class name to “PlayerViewController”.
    Screen Shot 2015-10-12 at 12.33.10 PM

  7. Before we can run this, as of iOS 9, we need to allow our app to access external URLs, like the one in our PlayerViewController that links to the video we’re playing.
  8. Click the Info.plist from the Project Navigator and add the keys below:
    Screen Shot 2015-10-12 at 12.35.22 PM

Watch Video

Lastly lets test to see if our video player works. Run the app, scroll to a video cell and click the Select button on the new Apple TV remote (or Enter key in the simulator) to play the video. You should see the screen below.

Screen Shot 2015-10-12 at 12.38.07 PM

There you have it, your own video app where users can browse through titles by category and select one to watch a video. Be sure to download the sample app below so you can see the full working app.

You can grab the full source code for this tutorial.
Note: Created using Xcode 7.1 GM (tvOS & Swift 2).

Tutorial: Deep Linking in SwifttvOS Tutorial: Top Shelf in Swift
Brian Coleman

Manager, Mobile Development at Rogers Communications with over 15 years of multifaceted experience including development, design, business analysis and project management working directly with clients in a consulting capacity throughout the full software life cycle.

October 13, 2015 Swift, Tutorials, tvOSswift, tutorial, tvos
Follow Me
    
Categories
  • About Me
  • Frameworks
  • My Apps
  • News
  • Strategy
  • Swift
  • Tools
  • Tutorials
  • tvOS
  • Uncategorized
  • Videos
  • Watch
Archives
  • May 2016
  • January 2016
  • October 2015
  • July 2015
  • May 2015
  • April 2015
  • March 2015
  • November 2014
  • October 2014
  • September 2014
  • July 2014
  • June 2014
  • September 2013
  • August 2013
  • July 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
Recent Posts
  • Classix for iPhone, iPad & Apple TV
  • Tutorial: How to test your app for IPv6 compatibility
  • Tutorial: Testing SSL using Charles Proxy on an iOS Device
  • Tutorial: 3D Touch – Quick Actions in Swift
  • tvOS Tutorial: Top Shelf in Swift
Featured Apps
Classix
Sportsnet
TAGS
tutorialswiftios8iosobjective-cvideogamesstrategynewsframeworkappsmonitizefacebookwatchappleios7toolstvosios9apiprovisionsocialtutorialsbooksdesignbookiapIPv6iTunes Connect
Search
TAGS
tutorialswiftios8iosobjective-cvideogamesstrategynewsframeworkappsmonitizefacebookwatchappleios7toolstvosios9apiprovisionsocialtutorialsbooksdesignbookiapIPv6iTunes Connect
ABOUT
Brian is a Lead iOS/tvOS Developer from Toronto with over 18 years of multifaceted experience including development, design, business analysis and project management.

FOLLOW ME
    
Email Subscription
Sign up for my newsletter to receive the latest news and tutorials posted.

Enter your email address:

2023 © Brian Coleman