{"id":1951,"date":"2015-09-10T19:42:12","date_gmt":"2015-09-11T01:42:12","guid":{"rendered":"http:\/\/jamesonquave.com\/blog\/?p=1951"},"modified":"2015-09-24T16:31:37","modified_gmt":"2015-09-24T22:31:37","slug":"developing-tvos-apps-for-apple-tv-part-2","status":"publish","type":"post","link":"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/","title":{"rendered":"Developing tvOS Apps for Apple TV [Part 2]"},"content":{"rendered":"<p><strong>Looking for some help building your Apple TV tvOS App? I&#8217;m available for consulting and development, <a href=\"mailto:jq@jqsoftware.com\">contact me<\/a>.<\/strong><\/p>\n<link href=\"http:\/\/alexgorbatchev.com\/pub\/sh\/current\/styles\/shThemeDefault.css\" rel=\"stylesheet\" type=\"text\/css\" \/><head><\/head><body>\n<p>This is part 2 of the tvOS tutorial. If you haven&#8217;t gone through <a href=\"http:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-with-swift\/\">part 1<\/a> yet, I suggest you run through that first.<\/p>\n<h2 id=\"adding-interactivity\">Adding Interactivity<\/h2>\n<p>In the first section we created a simple TVML document with a few buttons. It looked something like this:<\/p>\n<pre><code><div id=\"highlighter_123152\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"plain\">&lt;document&gt;<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;alertTemplate&gt;<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;title&gt;<\/code><code class=\"color2\">Hello<\/code> <code class=\"plain\">tvOS!&lt;\/title&gt;<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;button&gt;<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;text&gt;A <\/code><code class=\"color2\">Button<\/code><code class=\"plain\">&lt;\/text&gt;<\/code><\/div><div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/button&gt;<\/code><\/div><div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;button&gt;<\/code><\/div><div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;text&gt;A <\/code><code class=\"color2\">Second<\/code> <code class=\"color2\">Button<\/code><code class=\"plain\">&lt;\/text&gt;<\/code><\/div><div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/button&gt;<\/code><\/div><div class=\"line number10 index9 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/alertTemplate&gt;<\/code><\/div><div class=\"line number11 index10 alt2\"><code class=\"plain\">&lt;\/document&gt;<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>This is an alert with a few buttons, and they don&#8217;t do anything. It&#8217;s also rather specific and hard-coded, so maybe what would be better is to generate the XML on the fly. We can do this fairly easily in JS. Let&#8217;s add a new function to our main.js file that will encapsulate this alert in to a simpler alert with just an OK button.<\/p>\n<pre><code><div id=\"highlighter_345441\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"plain\">function alert(str) {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">alertXMLString = `&lt;?xml version=<\/code><code class=\"string\">\"1.0\"<\/code> <code class=\"plain\">encoding=<\/code><code class=\"string\">\"UTF-8\"<\/code> <code class=\"plain\">?&gt;<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;document&gt;<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;alertTemplate&gt;<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;title&gt;<\/code><code class=\"color2\">Hey<\/code> <code class=\"color2\">Listen<\/code><code class=\"plain\">!&lt;\/title&gt;<\/code><\/div><div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;description&gt;${str}&lt;\/description&gt;<\/code><\/div><div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;button&gt;<\/code><\/div><div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;text&gt;<\/code><code class=\"color2\">OK<\/code><code class=\"plain\">&lt;\/text&gt;<\/code><\/div><div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/button&gt;<\/code><\/div><div class=\"line number10 index9 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/alertTemplate&gt;<\/code><\/div><div class=\"line number11 index10 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/document&gt;`<\/code><\/div><div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">parser = <\/code><code class=\"keyword\">new<\/code> <code class=\"color2\">DOMParser<\/code><code class=\"plain\">();<\/code><\/div><div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">alertDOMElement = parser.parseFromString(alertXMLString, <\/code><code class=\"string\">\"application\/xml\"<\/code><code class=\"plain\">);<\/code><\/div><div class=\"line number14 index13 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">navigationDocument.presentModal(alertDOMElement);<\/code><\/div><div class=\"line number15 index14 alt2\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>What we&#8217;re doing here is creating a string called <code>alertXMLString<\/code> that contains the TVML contents of a simple alert template with just 1 button. However for the description we&#8217;re using the TVJS string concatenation <code>${variable}<\/code> to inject the value of <code>str<\/code>.<\/p>\n<p>Next, we create a new DOMParser object that converts this string in to an actual XML DOM element.<\/p>\n<p>Finally, we can present the DOM element modally using the presentModal method of the navigationDocument, a globally defined variable that will always contain the root navigation document.<\/p>\n<p>Now, in our onLaunch function, let&#8217;s remove the code we had from before and simply call an alert&#8230;<\/p>\n<pre><code><div id=\"highlighter_48719\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"color2\">App<\/code><code class=\"plain\">.onLaunch = function(options) {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">alert(<\/code><code class=\"string\">\"Hello!\"<\/code><code class=\"plain\">);<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p><img decoding=\"async\" src=\"\/tutImg\/tvOShelloAlert.png\" alt=\"tvOS Alert View\"><\/p>\n<p>Run the app and you&#8217;ll see a cool tvOS alert saying &#8220;Hello!&#8221; However, clicking OK does nothing. So how do we handle event&#8217;s such as touch?<\/p>\n<p>Basically, if you want to stay in JavaScript and TVML, you will want to add an event listener to the DOM element. So for example, we could add a second argument to the alert function, so that we can pass in a function that is called when the OK button sends the event for being &#8220;selected&#8221;. We&#8217;ll add this argument and call it <code>doneCallback<\/code>. To add the event listener, we can simply do so like this:<\/p>\n<pre><code><div id=\"highlighter_102052\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"plain\">alertDOMElement.addEventListener(<\/code><code class=\"string\">\"select\"<\/code><code class=\"plain\">, function() { doneCallback }, <\/code><code class=\"keyword\">false<\/code><code class=\"plain\">);<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>So after updating the entire function, it should look like this:<\/p>\n<pre><code><div id=\"highlighter_787518\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"plain\">function alert(str, doneCallback) {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">alertXMLString = `&lt;?xml version=<\/code><code class=\"string\">\"1.0\"<\/code> <code class=\"plain\">encoding=<\/code><code class=\"string\">\"UTF-8\"<\/code> <code class=\"plain\">?&gt;<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;document&gt;<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;alertTemplate&gt;<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;title&gt;<\/code><code class=\"color2\">Hey<\/code> <code class=\"color2\">Listen<\/code><code class=\"plain\">!&lt;\/title&gt;<\/code><\/div><div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;description&gt;${str}&lt;\/description&gt;<\/code><\/div><div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;button&gt;<\/code><\/div><div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;text&gt;<\/code><code class=\"color2\">OK<\/code><code class=\"plain\">&lt;\/text&gt;<\/code><\/div><div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/button&gt;<\/code><\/div><div class=\"line number10 index9 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/alertTemplate&gt;<\/code><\/div><div class=\"line number11 index10 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/document&gt;`<\/code><\/div><div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">parser = <\/code><code class=\"keyword\">new<\/code> <code class=\"color2\">DOMParser<\/code><code class=\"plain\">();<\/code><\/div><div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">alertDOMElement = parser.parseFromString(alertXMLString, <\/code><code class=\"string\">\"application\/xml\"<\/code><code class=\"plain\">);<\/code><\/div><div class=\"line number14 index13 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">alertDOMElement.addEventListener(<\/code><code class=\"string\">\"select\"<\/code><code class=\"plain\">, doneCallback, <\/code><code class=\"keyword\">false<\/code><code class=\"plain\">);<\/code><\/div><div class=\"line number15 index14 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">navigationDocument.presentModal(alertDOMElement);<\/code><\/div><div class=\"line number16 index15 alt1\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>Now, we can modify our original onLaunch function to add a callback function that will present a TVML screen. Before we do that, let&#8217;s also add a function called <code>getDocumentContents<\/code> which similarly implements a callback function when loading is done, which passes in the XMLHttpRequest object&#8217;s response to the callbacks only argument. This allows us to more easily load in various types of TVML files.<\/p>\n<pre><code><div id=\"highlighter_127477\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"plain\">function getDocumentContents(url, loadCallback) {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">templateXHR = <\/code><code class=\"keyword\">new<\/code> <code class=\"color2\">XMLHttpRequest<\/code><code class=\"plain\">();<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">templateXHR.responseType = <\/code><code class=\"string\">\"document\"<\/code><code class=\"plain\">;<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">templateXHR.addEventListener(<\/code><code class=\"string\">\"load\"<\/code><code class=\"plain\">, function() { loadCallback(templateXHR) }, <\/code><code class=\"keyword\">false<\/code><code class=\"plain\">);<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">templateXHR.open(<\/code><code class=\"string\">\"GET\"<\/code><code class=\"plain\">, url, <\/code><code class=\"keyword\">true<\/code><code class=\"plain\">);<\/code><\/div><div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"plain\">templateXHR.send();<\/code><\/div><div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code> <code class=\"plain\">templateXHR;<\/code><\/div><div class=\"line number8 index7 alt1\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>This is nearly the same code as the getDocument method we defined earlier, except this is asynchronous and does not actually push anything on to the view.<\/p>\n<p>Now, with this function we can perform this call and then do a screen replace of the alert when the OK button is clicked.<\/p>\n<pre><code><div id=\"highlighter_514041\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"color2\">App<\/code><code class=\"plain\">.onLaunch = function(options) {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">alert(<\/code><code class=\"string\">\"Hello!\"<\/code><code class=\"plain\">, function() {<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">helloDocument = getDocumentContents(<\/code><code class=\"string\">\"<a href=\"http:\/\/localhost:8000\/hello.tvml\">http:\/\/localhost:8000\/hello.tvml<\/a>\"<\/code><code class=\"plain\">, function(xhr) {<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">navigationDocument.dismissModal();<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">navigationDocument.pushDocument(xhr.responseXML);<\/code><\/div><div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">});<\/code><\/div><div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">});<\/code><\/div><div class=\"line number8 index7 alt1\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>Let&#8217;s also change our hello.tvml file to use the stackTemplate, since it&#8217;s more interesting to look at. A stackTemplate is a nice way to lay out a list of content with title&#8217;s and images. Here&#8217;s the example I&#8217;ll be using in my demo:<\/p>\n<pre><code><div id=\"highlighter_53496\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"plain\">&lt;document&gt;<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;stackTemplate&gt;<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;banner&gt;<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;title&gt;<\/code><code class=\"color2\">Which<\/code> <code class=\"color2\">Artist<\/code> <code class=\"color2\">Do<\/code> <code class=\"color2\">You<\/code> <code class=\"color2\">Prefer<\/code><code class=\"plain\">?&lt;\/title&gt;<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/banner&gt;<\/code><\/div><div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;collectionList&gt;<\/code><\/div><div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;shelf&gt;<\/code><\/div><div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;section&gt;<\/code><\/div><div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;lockup&gt;<\/code><\/div><div class=\"line number10 index9 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;img src=<\/code><code class=\"string\">\"<a href=\"http:\/\/localhost:8000\/nina.png\">http:\/\/localhost:8000\/nina.png<\/a>\"<\/code> <code class=\"plain\">width=<\/code><code class=\"string\">\"256\"<\/code> <code class=\"plain\">height=<\/code><code class=\"string\">\"256\"<\/code> <code class=\"plain\">\/&gt;<\/code><\/div><div class=\"line number11 index10 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;title&gt;<\/code><code class=\"color2\">Nina<\/code> <code class=\"color2\">Simone<\/code><code class=\"plain\">&lt;\/title&gt;<\/code><\/div><div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/lockup&gt;<\/code><\/div><div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;lockup&gt;<\/code><\/div><div class=\"line number14 index13 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;img src=<\/code><code class=\"string\">\"<a href=\"http:\/\/localhost:8000\/coltrane.png\">http:\/\/localhost:8000\/coltrane.png<\/a>\"<\/code> <code class=\"plain\">width=<\/code><code class=\"string\">\"256\"<\/code> <code class=\"plain\">height=<\/code><code class=\"string\">\"256\"<\/code> <code class=\"plain\">\/&gt;<\/code><\/div><div class=\"line number15 index14 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;title&gt;<\/code><code class=\"color2\">John<\/code> <code class=\"color2\">Coltrane<\/code><code class=\"plain\">&lt;\/title&gt;<\/code><\/div><div class=\"line number16 index15 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/lockup&gt;<\/code><\/div><div class=\"line number17 index16 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/section&gt;<\/code><\/div><div class=\"line number18 index17 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/shelf&gt;<\/code><\/div><div class=\"line number19 index18 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/collectionList&gt;<\/code><\/div><div class=\"line number20 index19 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">&lt;\/stackTemplate&gt;<\/code><\/div><div class=\"line number21 index20 alt2\"><code class=\"plain\">&lt;\/document&gt;<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>So basically this is just the way a stackTemplate is laid out, the banner is the top banner, the collectionList is just something that contains many shelf objects, which is just something that contains section objects, which contains lockup objects. The lockup object is what actually contains our image and title. In my case I added some images to work with to my directory called nina.png and coltrane.png<\/p>\n<p><img decoding=\"async\" src=\"\/tutImg\/tvOSArtists.png\" alt=\"tvOS stackTemplate Screenshot\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Looking for some help building your Apple TV tvOS App? I&#8217;m available for consulting and development, contact me. This is part 2 of the tvOS tutorial. If you haven&#8217;t gone through part 1 yet, I suggest you run through that first. Adding Interactivity In the first section we created a simple TVML document with a&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_links_to":"","_links_to_target":""},"categories":[75,10,71,74],"tags":[34,33,78,76],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.13 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Developing tvOS Apps for Apple TV [Part 2] - Jameson Quave<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Developing tvOS Apps for Apple TV [Part 2] - Jameson Quave\" \/>\n<meta property=\"og:description\" content=\"Looking for some help building your Apple TV tvOS App? I&#8217;m available for consulting and development, contact me. This is part 2 of the tvOS tutorial. If you haven&#8217;t gone through part 1 yet, I suggest you run through that first. Adding Interactivity In the first section we created a simple TVML document with a...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/\" \/>\n<meta property=\"og:site_name\" content=\"Jameson Quave\" \/>\n<meta property=\"article:published_time\" content=\"2015-09-11T01:42:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2015-09-24T22:31:37+00:00\" \/>\n<meta name=\"author\" content=\"Jameson Quave\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jameson Quave\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/\",\"url\":\"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/\",\"name\":\"Developing tvOS Apps for Apple TV [Part 2] - Jameson Quave\",\"isPartOf\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/#website\"},\"datePublished\":\"2015-09-11T01:42:12+00:00\",\"dateModified\":\"2015-09-24T22:31:37+00:00\",\"author\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc\"},\"breadcrumb\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/jamesonquave.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Developing tvOS Apps for Apple TV [Part 2]\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#website\",\"url\":\"https:\/\/jamesonquave.com\/blog\/\",\"name\":\"Jameson Quave\",\"description\":\"Using computer technology to educate, and improve lives.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/jamesonquave.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc\",\"name\":\"Jameson Quave\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg\",\"caption\":\"Jameson Quave\"},\"sameAs\":[\"http:\/\/jamesonquave.com\"],\"url\":\"https:\/\/jamesonquave.com\/blog\/author\/jquave\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Developing tvOS Apps for Apple TV [Part 2] - Jameson Quave","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/","og_locale":"en_US","og_type":"article","og_title":"Developing tvOS Apps for Apple TV [Part 2] - Jameson Quave","og_description":"Looking for some help building your Apple TV tvOS App? I&#8217;m available for consulting and development, contact me. This is part 2 of the tvOS tutorial. If you haven&#8217;t gone through part 1 yet, I suggest you run through that first. Adding Interactivity In the first section we created a simple TVML document with a...","og_url":"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/","og_site_name":"Jameson Quave","article_published_time":"2015-09-11T01:42:12+00:00","article_modified_time":"2015-09-24T22:31:37+00:00","author":"Jameson Quave","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Jameson Quave","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/","url":"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/","name":"Developing tvOS Apps for Apple TV [Part 2] - Jameson Quave","isPartOf":{"@id":"https:\/\/jamesonquave.com\/blog\/#website"},"datePublished":"2015-09-11T01:42:12+00:00","dateModified":"2015-09-24T22:31:37+00:00","author":{"@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc"},"breadcrumb":{"@id":"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/jamesonquave.com\/blog\/developing-tvos-apps-for-apple-tv-part-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/jamesonquave.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Developing tvOS Apps for Apple TV [Part 2]"}]},{"@type":"WebSite","@id":"https:\/\/jamesonquave.com\/blog\/#website","url":"https:\/\/jamesonquave.com\/blog\/","name":"Jameson Quave","description":"Using computer technology to educate, and improve lives.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jamesonquave.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc","name":"Jameson Quave","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg","caption":"Jameson Quave"},"sameAs":["http:\/\/jamesonquave.com"],"url":"https:\/\/jamesonquave.com\/blog\/author\/jquave\/"}]}},"_links":{"self":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/1951"}],"collection":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/comments?post=1951"}],"version-history":[{"count":3,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/1951\/revisions"}],"predecessor-version":[{"id":1967,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/1951\/revisions\/1967"}],"wp:attachment":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/media?parent=1951"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/categories?post=1951"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/tags?post=1951"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}