Статьи

DeviceIady от Ionic и Cordova: мое решение

Люди знают, что в последнее время я безумно влюблен в Ionic Framework , но я столкнулся с проблемой, с которой у меня возникли трудности. Я думал, что буду писать в блоге о проблеме и продемонстрирую решение, которое сработало для меня. Чтобы быть ясным, я думаю, что мое решение, вероятно, неправильно . Это работает, но это просто не чувствовать себя хорошо. Я специально делюсь этой записью в блоге, чтобы начать обсуждение и получить отзывы. По маловероятной вероятности, что то, что я показываю, является лучшим решением … хм … да … Я планировал это. Я великолепен.

Эта проблема

Итак, начнем с обсуждения проблемы. Учитывая типичное приложение Ionic, ваш Angular-код будет иметь метод .run, который прослушивает событие готовности ionicPlatform. Вот пример из «базового» начального приложения ( https://github.com/driftyco/ionic-app-base/blob/master/www/js/app.js ):

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('starter', ['ionic'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      // Set the statusbar to use the default style, tweak this to
      // remove the status bar on iOS or change it to use white instead of dark colors.
      StatusBar.styleDefault();
    }
  });
})

Событие ionicPlatform.ready вызывается, когда происходит событие устройства Cready в Cordova. Когда запускается на рабочем столе, он запускается в окне window.load. Хорошо, так что, на мой взгляд, я бы поместил код, который обычно находится в блоке document.ready. Все идет нормально.

Теперь давайте представим, что вы хотите использовать плагин, возможно плагин Device. Представьте, что вы хотите просто скопировать значение в $ scope, чтобы вы могли отобразить его в виде. Если этот контроллер / представление является первым представлением в вашем приложении, вы в конечном итоге получите состояние гонки. Angular будет отображать ваш вид и запускать ionicPlatform. Уже асинхронно. Это не ошибка, конечно, но это поднимает вопрос. Если вы хотите использовать функции плагина Cordova, и ваше приложение сразу же от него зависит , как вы справитесь с этим?

Одним из способов было бы удалить ng-app из DOM и самостоятельно загрузить Angular. Я сделал это … однажды, и я вижу, как это имеет смысл. Но я не хотел использовать это решение на этот раз, так как я хотел продолжать использовать ionicPlatform.ready. Я предположил (и могу ошибаться!), Что не могу сохранить это и удалить загрузчик ng-app.

Поэтому я добавил промежуточное представление к своему приложению. Простая целевая страница. Я изменил stateProvider, чтобы добавить новое состояние, а затем сделал его по умолчанию. В моем ionicPlatform.ready я использую сервис определения местоположения, чтобы перейти в предыдущее состояние по умолчанию.

.run(function($ionicPlatform,$location,$rootScope) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

  $location.path('/tab/dash');
  $rootScope.$apply();
  });
})

Казалось, это сработало. Мой код контроллера, который запускается для представлений после этого, смог использовать плагины Cordova очень хорошо. Как насчет реального примера?

Демо

Одной из последних функций, появившихся в Ionic, являются вкладки в полосатом стиле . Это пользовательский интерфейс в стиле Android, и он будет автоматически применяться к приложениям, работающим на Android. Разница немного тонкая, когда вкладки находятся внизу:

Но при перемещении наверх с помощью tabs-top, это немного более драматично.

Ладно, круто. Но мне было интересно — как я могу получить вкладки сверху только для Android? Хотя я не из тех людей, которые считают, что элементы пользовательского интерфейса должны быть в определенной позиции на iOS по сравнению с Android, мне было любопытно, как бы я справился с этим программно.

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

Вот файл app.js, который я использовал, модифицированный из начального шаблона вкладок.

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])

.run(function($ionicPlatform,$location,$rootScope) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

  $location.path('/tab/dash');
  $rootScope.$apply();
  });
})

.config(function($stateProvider, $urlRouterProvider) {

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

    // setup an abstract state for the tabs directive
  .state('home', {
url:"/home",
templateUrl:'templates/loading.html',
controller:'HomeCtrl'
})
    .state('tab', {
      url: "/tab",
      abstract: true,
      templateUrl: function() {
  if(window.device.platform.toLowerCase().indexOf("android") >= 0) {
  return "templates/tabs_android.html";  
  } else {
  return "templates/tabs.html";
  }
  },
    })

    // Each tab has its own nav history stack:

    .state('tab.dash', {
      url: '/dash',
      views: {
        'tab-dash': {
          templateUrl: 'templates/tab-dash.html',
          controller: 'DashCtrl'
        }
      }
    })

    .state('tab.friends', {
      url: '/friends',
      views: {
        'tab-friends': {
          templateUrl: 'templates/tab-friends.html',
          controller: 'FriendsCtrl'
        }
      }
    })
    .state('tab.friend-detail', {
      url: '/friend/:friendId',
      views: {
        'tab-friends': {
          templateUrl: 'templates/friend-detail.html',
          controller: 'FriendDetailCtrl'
        }
      }
    })

    .state('tab.account', {
      url: '/account',
      views: {
        'tab-account': {
          templateUrl: 'templates/tab-account.html',
          controller: 'AccountCtrl'
        }
      }
    });

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/home');

});

Вы можете увидеть, где я использую механизм location.path после того, как произошло событие ionicPlatform.ready. Вы также можете увидеть, где я нюхаю платформу устройства, чтобы определить, какой шаблон запустить. tabs_android.html точно такой же, как tabs.html, но с примененным классом tabs-top (*). Самым большим недостатком здесь является то, что приложение будет иметь ошибку при запуске на рабочем столе. Этого можно избежать, прослушивая отсутствие window.device и просто установив для него значение по умолчанию:window.device = {platform : "ios"};

Итак, это все. Как вы думаете? Я должен представить, что есть более хороший способ справиться с этим. Может быть, я ленивый, но я хочу использовать директивы Ionic и UX вместе с плагинами Cordova, и мне не нужно использовать такой неуклюжий обходной путь, как этот.

* Быстрая сноска. Я заметил, что если я попытаюсь добавить tabs-top в директиву ion-tabs, это никогда не сработает. Например, это то, что я попробовал в первую очередь: <ion-tabs ng-class="{'tabs-top':settings.isAndroid}">я использовал код в моем контроллере, который всегда устанавливал его в true (я еще не беспокоился о плагине устройства), и он фактически никогда не обновлял представление. Как будто область видимости контроллера не может изменить представление по какой-то странной причине.