По результатам опроса из первого топика продолжаю серию статей об Ionic Framework (далее IF). Сегодня поговорим о работе с камерой устройства и в дополнение рассмотрим работу с localStorage. В качестве основы возьмем приложение из прошлого топика и добавим нужную функциональность.
Добавление ngCordova
Для работы установленных плагинов необходимо добавить модуль ngCordova. Ставится он просто (для начала обновим наши инструменты, ведь прошло много времени с момента публикации первой статьи...):
sudo npm i -g cordova ionic bower
bower install ngCordova
Далее ngCordova подключается в index.html:
<script src="lib/ngCordova/dist/ng-cordova.min.js"></script>
и в зависимости приложения (app.js):
angular.module('starter', ['ionic', 'ngCordova', 'starter.controllers', 'starter.services'])
иначе паровозик не сможет… Желательно также подключить еще пару плагинов для работы с ФС устройства:
ionic plugin add cordova-plugin-file
ionic plugin add cordova-plugin-file-transfer
По идее можно было бы подключить только file-transfer, т.к. вместе с собой он также тянет и file, но иногда такой способ чреват появлением непонятных багов…
Подключение плагина для работы с камерой
Для того чтобы IF смог получить доступ к камере устройства нужно добавить в проект Cordova плагин реализующий этот функционал:
ionic plugin add cordova-plugin-camera
Плагин предоставляет единственный метод:
navigator.camera.getPicture(SuccessCallback, ErrorCallback, Options);
Где SuccessCallback и ErrorCallback это наши функции-обработчики в которых мы вольны писать все что вздумается, а вот объект Options гораздо интереснее для рассмотрения:
Настройки для камеры
- quality (Number): Качество сохраняемого изображения, в интервале от 0 до 100, где 100 — режим без сжатия. По умолчанию значение 50.
- destinationType(Number): Формат возвращаемого значения. По умолчанию FILEURI. Настройка определяется типами navigator.camera.DestinationType:
Camera.DestinationType = { DATA_URL : 0, // Строка в формате base64 FILE_URI : 1, // URI файла NATIVE_URI : 2 // URI пути зависящий от платформы (assets-library:// для iOS и content:// для Android) };
- sourceType (Number): Источник изображения. По умолчанию CAMERA. Настройка определяется типами navigator.camera.PictureSourceType:
Camera.PictureSourceType = { PHOTOLIBRARY : 0, CAMERA : 1, SAVEDPHOTOALBUM : 2 };
- allowEdit (Boolean): Включает режим простого редактирования перед передачей в функцию.
- encodingType (Number): Формат файла. По умолчанию «у вас JPEG». Настройка определяется типами navigator.camera.EncodingType:
Camera.EncodingType = { JPEG : 0, // JPEG PNG : 1 // PNG };
- targetWidth (Number): Ширина. Без комментариев. Для масштабирования. Лучше использовать в связке с targetHeight с коэффициентом.
- targetHeight (Number): Высота.
- mediaType (Number): Тип мультимедиа контента. По умолчанию PICTURE. Работает при PictureSourceType равным PHOTOLIBRARY или SAVEDPHOTOALBUM. Настройка определяется типами nagivator.camera.MediaType:
Camera.MediaType = { PICTURE: 0, // Только изображения. VIDEO: 1, // Только видео (ВСЕГДА ВОЗВРАЩАЕТ FILE_URI) ALLMEDIA : 2 // Все типы };
- correctOrientation (Boolean): Поворот изображения для компенсации ориентации устройства во время съемки.
- saveToPhotoAlbum (Boolean): Сохранение в альбом после съемки.
- popoverOptions: iOS-only параметр определяющий местонахождение popover на iPad. Настройка определяется в CameraPopoverOptions.
- cameraDirection (Number): Камера для использования (фронтальная или задняя). По умолчанию BACK. Настройка определяется типами navigator.camera.Direction:
Camera.Direction = { BACK : 0, // Use the back-facing camera FRONT : 1 // Use the front-facing camera };
Вот в принципе и все что можно рассказать…
Создание сервиса для работы с камерой
Давайте для нашего удобства сделаем службу чтобы работа с камерой была комфортной. Для этого предлагаю реализовать фабрику с объектом promise который будет обрабатывать события камеры с помощью наших callback'ов. Откройте файл services.js (в прошлом топике мы уже сделали там фабрику городов) и приведите его к такому виду:
services.js
angular.module('starter.services', [])
.factory('Cities', function() {
// ...
}).factory('Cam', function($q) {
return {
getPic: function(opt) {
var q = $q.defer();
navigator.camera.getPicture(function(res) {
q.resolve(res);
}, function(err) {
q.reject(err);
}, opt);
return q.promise;
}
};
});
Итак, в этой настройке мы, используя Angular'овский $q.defer(), возвращаем promise, которому впоследствии передадим обработчики событий с камеры (SuccessCallback, ErrorCallback) и объект настройки (Options). Не закрывайте файл, мы к нему еще вернемся!
Редактирование шаблонов
Откройте файл tabs.html и добавьте еще один tab. У меня получился такой:
<ion-tab title="Options" icon-off="ion-gear-a" icon-on="ion-gear-a" href="#/tab/opt">
<ion-nav-view name="tab-opt"></ion-nav-view>
</ion-tab>
Теперь в папке с шаблонами создадим еще один шаблон (например tab-opt.html) и сделаем небольшую форму настройки пользователя приложения, например такую:
tab-opt.html
<ion-view view-title="Настройки">
<ion-content class="padding">
<div class="list-item">
<img class="full-image" ng-src="{{user.ava || './img/ionic.png'}}">
<label class="item item-input">
<i class="icon ion-person placeholder-icon"></i>
<input type="text" placeholder="Имя пользователя" ng-model="user.name" ng-keyup="setUser();" />
</label>
<label class="item item-input item-select">
<div class="input-label">
Город
</div>
<select ng-model="user.city" ng-change="setUser();">
<option ng-repeat="city in cities" ng-value="city.id">{{city.name}}</option>
</select>
</label>
<button class="button button-full button-positive" ng-click="getPic(1);">
С камеры
</button>
<button class="button button-full button-calm" ng-click="getPic(0);">
Из библиотеки
</button>
</div>
</ion-content>
</ion-view>
Как видно, к полям мы привязали модель пользователя и при изменении значения поля html, в модели будет изменяться соответствующее поле объекта. Так же на события когда клавиша отпущена (кстати, тут можно использовать debounce) и на изменение выбора города, была сделана привязка обработчика setUser, это все мы опишем на следующем шаге. Не терпится запустить и посмотреть? Но мы еще не настроили маршрутизацию, контроллеры и работу с localStorage, так что придется еще немного подождать…
Добавление маршрутов, контроллеров и фабрик
Займемся для начала маршрутами. Откройте app.js и добавьте маршрутизацию для нашего нового таба:
Подсказка
.state('tab.opt', {
url: '/opt',
views: {
'tab-opt': {
templateUrl: 'templates/tab-opt.html',
controller: 'OptCtrl'
}
}
})
Отлично, теперь перейдем в controllers.js и добавим нужный контроллер:
OptCtrl
.controller('OptCtrl', function($scope, $ionicPopup, Cities, Cam, LS) {
$scope.cities = Cities.all();
$scope.user = LS.getIt('user') || {};
$scope.showAlert = function(title, text) {
$ionicPopup.alert({
title: title,
template: text
});
};
$scope.setUser = function() {
LS.setIt('user', $scope.user);
};
$scope.getPic = function(source) {
var opt = {
sourceType: source
};
Cam.getPic(opt).then(function(res) {
$scope.user.ava = res;
$scope.setUser();
}, function(err) {
$scope.showAlert("Ошибка", err);
});
}
})
Оппа, что за LS в зависимостях контроллера!? Ничего не бойтесь, это всего лишь метод для работы с localStorage, и настало время его реализовать (services.js):
LS
.factory('LS', function() {
return {
getIt: function(item) {
var it = false;
try {
it = JSON.parse(localStorage.getItem(item));
return it;
} catch(e) {
console.err(e);
return it;
}
},
setIt: function(item, obj) {
try {
localStorage.setItem(item, JSON.stringify(obj));
return true;
} catch(e) {
console.err(e);
return false;
}
}
};
})
И надо бы добавить еще городов, добавьте свой:
{
id: 555312,
name: 'Иваново',
desc: 'Город невест',
emblem: 'http://ift.tt/1MPOeBB'
}
Вы сейчас наверное думаете «к чему столько телодвижений?». А представьте себе, что пользователь настроил город (автоматически сохранив в localStorage) и при повторном запуске приложения его будет сразу перекидывать на погоду в родном городе, круто же! Финальный штрих, изменим два наших контроллера, написанных в прошлой статье:
CityCtrl, CityDetailCtrl
.controller('CityCtrl', function($scope, Cities, LS) {
$scope.cities = Cities.all();
$scope.user = LS.getIt('user') || {};
if ($scope.user.city) { window.location.href = '#/tab/city/'+$scope.user.city; }
})
.controller('CityDetailCtrl', function($scope, $http, $stateParams, $ionicPopup, $ionicLoading) {
$scope.data = {};
$scope.id = $stateParams.id;
$scope.showAlert = function(title, text) {
$ionicPopup.alert({
title: title,
template: text
});
};
$scope.refresh = function() {
$ionicLoading.show();
$http.get('http://ift.tt/1MzxSJU'+$scope.id+'&appid=2de143494c0b295cca9337e1e96b00e0')
.success(function(data, status, headers, config) {
$scope.data = data;
$ionicLoading.hide();
$scope.$broadcast('scroll.refreshComplete');
})
.error(function(data, status, headers, config) {
$ionicLoading.hide();
$scope.showAlert(status, data);
$scope.$broadcast('scroll.refreshComplete');
});
};
$scope.refresh();
})
Мы добавили условие, чтобы пользователя перекидывало на настроенный город, а также незаметно указали в зависимостях компонент $ionicLoading для показа окна ожидания во время запроса. Надеюсь ничего не пропустил, все готово, вы знаете что делать (ionic serve --lab, если забыли):
It works!
Заключение
В принципе на текущий момент работать с помощью IF становится всё удобнее и проще, поэтому я смело могу сказать что это один из лучших фреймворков для прототипирования, и даже для production приложений. Дерзайте! В следующей статье хочу описать создание чата с помощью socket.io и работу с ещё кое-чем интересным ;). Если у вас появились трудности, вопросы или предложения для следующих статей — милости прошу в ЛС!
This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий