(часть 5 из 5)

Это последняя часть нашего руководства по tvOS. Ознакомьтесь с предыдущими страницами, чтобы узнать больше об этой серии.

catalogTemplate — это один из 18 шаблонов, доступных для использования разработчиками tvOS. Цель шаблона — отображать информацию о группах похожих товаров, что идеально подходит для демонстрации ваших видео на основе их категорий! В catalogTemplate есть много интересных элементов:

Баннер — этот элемент используется для отображения информации в верхней части страницы шаблона приложения. Он состоит из нескольких простых элементов, таких как заголовок, фон и т. д.

Давайте начнем его создавать, перейдите в каталог client и создайте две новые папки в папке js и назовите их images и templates соответственно. Папка вашего клиента теперь должна иметь следующие папки.

Вам понадобятся изображения для заполнения ячеек в шаблоне каталога. Нажмите здесь, чтобы загрузить их, я собрал их для вас с помощью некоторых обучающих сайтов. После загрузки перенесите изображения в папку images, которую вы создали в каталоге client.

Теперь вы собираетесь отображать изображения на экране! Создайте новый файл JavaScript с именем HighlightsTemplate.xml.js в папке templates.

Добавьте следующее в HighlightsTemplate.xml.js:

var Template = function() { return `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <catalogTemplate>
      <banner>
        <title>Highlights</title>
      </banner>
    </catalogTemplate>
  </document>`
}

Пока попробуем отобразить только баннер из catalogTemplate.

Наконец, наш последний файл Javascript, ResourceLoader.js, который помогает нам сообщить другим файлам о существовании файла шаблона.

ResourceLoader

Создайте новый файл JavaScript, назовите его ResourceLoader.js и сохраните в папке js вместе с файлами application.js и >файлы Presenter.js.

Добавьте в ResourceLoader.js следующее:

 
function ResourceLoader(baseurl) {
  this.BASEURL = baseurl;
}
 
ResourceLoader.prototype.loadResource = function(resource, callback) {
  var self = this;
  evaluateScripts([resource], function(success) {
    if(success) {
      var resource = Template.call(self);
      callback.call(self, resource);
    } else {
      var title = "Resource Loader Error",
          description = `Error loading resource '${resource}'. \n\n Try again later.`,
          alert = createAlert(title, description);
      navigationDocument.presentModal(alert);
    }
  }); 
}

Не тратьте много времени на анализ этого файла, просто знайте, что этот файл используется для загрузки файлов шаблонов.

Теперь давайте попробуем заменить наше оповещение «Hello World» нашим недавно созданным HighlightsTemplate в качестве основного экрана. Откройте application.js и внесите в файл следующие изменения:

// 1
var resourceLoader;
 
App.onLaunch = function(options) {
  // 2
  var javascriptFiles = [
    `${options.BASEURL}js/ResourceLoader.js`, 
    `${options.BASEURL}js/Presenter.js`
  ];
 
  evaluateScripts(javascriptFiles, function(success) {
    if(success) {
      // 3
      resourceLoader = new ResourceLoader(options.BASEURL);
      resourceLoader.loadResource(`${options.BASEURL}templates/HighlightsTemplate.xml.js`, function(resource) {
        var doc = Presenter.makeDocument(resource);
        Presenter.pushDocument(doc);
      });
    } else {
      var errorDoc = createAlert("Evaluate Scripts Error", "Error attempting to evaluate external JavaScript files.");
      navigationDocument.presentModal(errorDoc);
    }
  });
}

// Leave createAlert alone

Пояснение к коду:

  1. Объявлена ​​переменная resourceLoader.
  2. Добавлен ResourceLoader.js в список файлов, которые мы хотим предоставить.
  3. Использовали переменную resourceLoader со значением 1 для загрузки шаблона TVML и использовали Presenter для его представления на экране.

Соберите и запустите проект и убедитесь, что у вас нет ошибок. Не стесняйтесь оставлять комментарии или писать на мой mailID в случае каких-либо ошибок/сомнений.

Поздравляем, теперь вы можете загружать TVML из файла, а не жестко кодировать его в свой Javascript!

Создайте еще несколько TVML

Хотите верьте, хотите нет, но вы почти закончили. Одна из самых прекрасных особенностей приложений TVML для tvOS заключается в том, что в них очень легко добавлять элементы пользовательского интерфейса.

var Template = function() { return `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <catalogTemplate>
      <banner>
        <title>Highlights</title>
      </banner>
  //1
      <list>
        <section> 
  //2
      <listItemLockup>
        <title>Inspiration Videos</title>
        <decorationLabel>13</decorationLabel>
  //3
        <relatedContent>
          <grid>
            <section>
  //4
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/ray.png" width="500" height="308" />
          </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/ryan.png" width="500" height="308" />
          </lockup>
              <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/matthijs.png" width="500" height="308" />
          </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/vicki.png" width="500" height="308" />
          </lockup>
              <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/alexis.png" width="500" height="308" />
              </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/marin.png" width="500" height="308" />
          </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/chris.png" width="500" height="308" />
              </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/cesare.png" width="500" height="308" />
          </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/ellen.png" width="500" height="308" />
          </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/jake.png" width="500" height="308" />
          </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/kim.png" width="500" height="308" />
          </lockup>
              <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/tammy.png" width="500" height="308" />
          </lockup>
          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
            <img src="${this.BASEURL}images/saul.png" width="500" height="308" />
          </lockup>
        </section>
          </grid>
        </relatedContent>
      </listItemLockup>
  
        <listItemLockup>
          <title>Funny Videos</title>
          <decorationLabel>3</decorationLabel>
          <relatedContent>
            <grid>
              <section>
                      <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                        <img src="${this.BASEURL}images/kim.png" width="500" height="308" />
                      </lockup>
                          <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                        <img src="${this.BASEURL}images/tammy.png" width="500" height="308" />
                      </lockup>
                      <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                        <img src="${this.BASEURL}images/saul.png" width="500" height="308" />
                      </lockup>
  
          </section>
            </grid>
          </relatedContent>
        </listItemLockup>
  
          <listItemLockup>
            <title>Educational Videos</title>
            <decorationLabel>4</decorationLabel>
            <relatedContent>
              <grid>
                <section>
                      <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                        <img src="${this.BASEURL}images/cesare.png" width="500" height="308" />
                      </lockup>
                      <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                        <img src="${this.BASEURL}images/ellen.png" width="500" height="308" />
                      </lockup>
                      <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                        <img src="${this.BASEURL}images/jake.png" width="500" height="308" />
                      </lockup>
                      <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                        <img src="${this.BASEURL}images/kim.png" width="500" height="308" />
                      </lockup>
    
            </section>
              </grid>
            </relatedContent>
          </listItemLockup>
  
            <listItemLockup>
              <title>Anime Videos</title>
              <decorationLabel>3</decorationLabel>
              <relatedContent>
                <grid>
                  <section>
                                  <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                                    <img src="${this.BASEURL}images/vicki.png" width="500" height="308" />
                                  </lockup>
                                      <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                                    <img src="${this.BASEURL}images/alexis.png" width="500" height="308" />
                                      </lockup>
                                  <lockup videoURL="https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8">
                                    <img src="${this.BASEURL}images/marin.png" width="500" height="308" />
                                  </lockup>
      
              </section>
                </grid>
              </relatedContent>
            </listItemLockup>
  
        </section>
      </list>
    </catalogTemplate>
  </document>`
}

Пояснение кода:

  1. Область Список, которая охватывает остальную часть содержимого экрана.
  2. listItemLockup — представляет ячейку раздела. Каждая ячейка представлена ​​с помощью тега listItemLockup. Мы объявили различные разделы, такие как «Вдохновляющие видео», «Смешные видео», «Образовательные видео» и «Аниме-видео».
  3. relatedContent — этот тег относится к области, прилегающей к первому разделу.
  4. lockup — этот тег ссылается на ячейку в сетке. Мы включили свойство videoURL для каждого тега блокировки. Это будет необходимо для потоковой передачи видео.

Создайте и запустите свое приложение.

Теперь, когда у нас есть много разных ячеек, с которыми можно поиграться, давайте выведем пульт дистанционного управления в симулятор (с активным окном симулятора щелкните окно и покажите пульт AppleTV). Вы можете перемещаться по ячейкам, просто удерживая клавишу option и перемещая курсор в удаленном окне.

Потоковое видео

На данный момент у нас есть домашний экран, и он выглядит великолепно. Apple действительно проделала большую работу, абстрагируясь от всех деталей, предоставив нам эти фантастические шаблоны для работы. Только представьте, сколько времени уйдет на то, чтобы спроектировать все это с помощью UIKit.

Давайте перейдем к следующей части и реализуем последние две функции этого приложения: выбор ячейки и воспроизведение мультимедиа.

События выбора

Возможно, вы уже заметили, что нажатие клавиши ввода или нажатие кнопки Пульт Apple TV Remote вызывает анимацию нажатия, но ничего не происходит. Теперь мы собираемся реализовать необходимый код для реализации выбора ячеек.

Как мы уже знаем, эту часть будет обрабатывать класс Presenter. Добавьте следующий код в класс Presenter:

load: function(event) {
  //1
  var self = this,
  ele = event.target,
  videoURL = ele.getAttribute("videoURL")
  if(videoURL) {
    //2
    var player = new Player();
    var playlist = new Playlist();
    var mediaItem = new MediaItem("video", videoURL);

    player.playlist = playlist;
    player.playlist.push(mediaItem);
    player.present();
  }
}

Пояснение кода:

Давайте проведем сравнительное исследование для лучшего понимания кода.

  1. load — этот метод отвечает за выбор ячеек. Он аналогичен @IBAction, а аргумент event подобен отправителю IBAction. У каждого события есть цель, и цель относится к каждому элементу блокировки. [ПРИМЕЧАНИЕ: блокировка представляет каждую ячейку в нашем разделе миниатюрой видео, и каждая из них имеет свойство videoURL]
  2. Player — этот класс платформы TVJS предоставляет все функции воспроизведения мультимедиа. Вам просто нужно добавить список воспроизведения и вставить элемент mediaItem в список воспроизведения, и, наконец, player.present() воспроизведет видео на экране. .

Теперь, когда мы реализовали логику реагирования на события выбора, пришло время подключить ее к каждой ячейке. В последний раз вернитесь к файлу application.js и добавьте следующую строку в метод App.onLaunch.

App.onLaunch = function(options) {
  //...
  //inside resourceLoader.loadResource...
  var doc = Presenter.makeDocument(resource);
  doc.addEventListener("select", Presenter.load.bind(Presenter)); //add this line
  Presenter.pushDocument(doc);
  //...
}

Метод addEventListener аналогичен подключению кнопки к выходу @IBAction. Создайте и запустите свой проект, и теперь, когда вы нажимаете на ячейку, будет воспроизводиться соответствующее видео.

Ура! Мы прошли очень долгий путь. Теперь пришло время веселиться, хлопнуть себя по спине и начать пробовать разные шаблоны.

Не только об ошибках, я также хотел бы услышать от вас, ребята, поэтому не стесняйтесь делиться своими отзывами в разделе комментариев или на мой почтовый идентификатор [email protected], и я обязательно свяжусь с вами. вы как можно скорее.

На этом пока все, догоним вас, ребята, в моей следующей статье о tvOS с использованием родного UIKit, мы создадим приложение, похожее на платформу OTT.

Справочные ссылки:





https://www.kodeco.com/home