Статьи

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

В прошлой статье я познакомил вас с NativeScript . Там вы узнали основы NativeScript и его отличие от других мобильных сред разработки. На этот раз вы испачкаете руки, создав первое приложение NativeScript. Я проведу вас через весь процесс создания приложения с помощью NativeScript, от настройки среды разработки до запуска приложения на вашем устройстве. Вот схема того, что я буду обсуждать:

  1. Настройка NativeScript
  2. Сборка приложения
  3. Запуск приложения
  4. Отладка приложения

Мы специально запустим приложение на платформе Android. Но вы все равно можете следовать, если вы хотите развернуть на iOS, так как код будет почти таким же. Единственные различия заключаются в процессе настройки NativeScript и командах, которые вы выполняете при запуске приложения.

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

Чтобы настроить NativeScript, сначала необходимо установить Node.js. После установки Node.js вы можете установить инструмент командной строки NativeScript, npm install -g nativescript на своем терминале npm install -g nativescript .

Последний шаг — установить инструмент разработки для каждой платформы, на которой вы хотите выполнить развертывание. Для Android это Android SDK. Для iOS это XCode. Вы можете следовать руководству по установке на веб-сайте NativeScript для получения более подробных инструкций по настройке необходимого программного обеспечения для вашей среды разработки.

После настройки среды выполните tns doctor чтобы убедиться, что ваша среда готова для разработки на NativeScript. Если вы используете Linux или Windows, вы увидите что-то вроде этого, если ваша среда готова:

1
2
3
4
5
6
NOTE: You can develop for iOS only on Mac OS X systems.
 
To be able to work with iOS devices and projects, you need Mac OS X Mavericks or later.
Your components are up-to-date.
 
No issues were detected.

Там есть примечание, что вы можете разрабатывать только для iOS только в системах Mac OS X. Это означает, что если вы находитесь на ПК, вы сможете развертывать только на устройствах Android. Однако, если вы работаете на Mac, вы сможете развернуть его на платформах iOS и Android.

Если у вас возникнут какие-либо проблемы во время установки, вы можете получить приглашение присоединиться к сообществу NativeScript Slack, а после присоединения перейти на канал «Начало работы» и задать свои вопросы.

Приложение, которое мы собираемся создать, — это приложение для заметок. Это позволит пользователю создавать заметки, каждая с дополнительным вложением изображения, которое будет захвачено камерой устройства. Примечания сохраняются с использованием настроек приложения NativeScript и могут быть удалены по отдельности.

Вот как будет выглядеть приложение:

Приложение NativeScript

Начните с выполнения следующей команды для создания нового проекта NativeScript:

1
tns create noter —appid «com.yourname.noter»

noter — это имя проекта, а com.yourname.noter — уникальный идентификатор приложения. Позже это будет использовано для идентификации вашего приложения после его отправки в Play или App Store. По умолчанию команда tns create создаст для вас следующие папки и файлы:

  • приложение
  • node_modules
  • платформы
  • package.json

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

Затем перейдите в каталог приложения и удалите все файлы, кроме папки App_Resources . Затем создайте следующие файлы:

  • app.js
  • app.css
  • Заметки-page.js
  • ноты-page.xml

Это файлы, которые будут использоваться средой выполнения NativeScript. Как и при создании веб-страниц, файлы .css используются для стилей, а файлы .js — для функциональности. Но для разметки приложения мы используем XML вместо HTML. Обычно вы создаете отдельную папку для каждого экрана приложения (например, вход в систему, регистрация или панель инструментов) и в каждой папке есть файлы XML, CSS и JavaScript. Но так как это приложение имеет только один экран, мы создали все файлы внутри корневого каталога.

Если вам нужна дополнительная информация о структуре каталогов NativeScript, ознакомьтесь с главой 2 Руководства по началу работы с NativeScript .

Откройте файл app.js и добавьте следующий код:

1
2
var application = require(«application»);
application.start({ moduleName: «notes-page» });

Это точка входа для приложения NativeScript. Он использует модуль приложения и его метод start чтобы указать модуль, используемый для начальной страницы приложения. В данном случае мы указали notes-page , что означает, что модуль — notes-page.js , разметка — notes-page.xml , а стиль страницы — notes-page.css . Это соглашение, используемое в NativeScript, что все файлы для конкретной страницы должны иметь одинаковые имена.

Откройте файл notes-page.xml и добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<Page xmlns=»http://schemas.nativescript.org/tns.xsd» loaded=»pageLoaded»>
    <Page.actionBar>
        <ActionBar title=»{{ app_title }}»>
            <ActionBar.actionItems>
                <ActionItem tap=»newNote» ios.position=»right» android.position=»actionBar»>
                    <ActionItem.actionView>
                        <StackLayout orientation=»horizontal»>
                            <Label text=»New Item» color=»#fff» cssClass=»header-item» />
                        </StackLayout>
                    </ActionItem.actionView>
                </ActionItem>
            </ActionBar.actionItems>
        </ActionBar>
    </Page.actionBar>
 
    <StackLayout>
        <StackLayout id=»form» cssClass=»form-container»>
            <TextView text=»{{ item_title }}» hint=»Title» />
            <Button text=»Attach Image» cssClass=»link label» tap=»openCamera» />
            <Image src=»{{ attachment_img }}» id=»attachment_img» cssClass=»image» visibility=»{{ attachment_img ? ‘visible’ : ‘collapsed’ }}» />
            <Button text=»Save Note» tap=»saveNote» cssClass=»primary-button» />
        </StackLayout>
           
        <ListView items=»{{ notes }}» id=»list» visibility=»{{ showForm ? ‘collapsed’ : ‘visible’ }}»>
            <ListView.itemTemplate>
                <GridLayout columns=»*,*» rows=»auto,auto» cssClass=»item»>
                    <Label text=»{{ title }}» textWrap=»true» row=»0″ col=»0″ />
                    <Image src=»{{ photo }}» horizontalAlignment=»center» verticalAlignment=»center» cssClass=»image» row=»1″ col=»0″ visibility=»{{ photo ? ‘visible’ : ‘collapsed’ }}» />
                    <Button text=»delete» index=»{{ index }}» cssClass=»delete-button» tap=»deleteNote» row=»0″ col=»1″ horizontalAlignment=»right» loaded=»btnLoaded» />
                </GridLayout>
            </ListView.itemTemplate>
        </ListView>
    </StackLayout>
</Page>

При создании страниц приложения в NativeScript вы всегда должны начинать с <Page> . Вот как NativeScript узнает, что вы пытаетесь создать новую страницу. Атрибут xmlns указывает URL-адрес схемы, используемой для файла XML.

Если вы посетите указанный URL-адрес схемы , вы увидите определение всех тегов XML, которые вы можете использовать в NativeScript. Атрибут loaded определяет функцию, которая будет выполняться после загрузки страницы. Мы рассмотрим это определение функции позже в файле notes-page.js .

1
2
3
<Page xmlns=»http://schemas.nativescript.org/tns.xsd» loaded=»pageLoaded»>
 …
</Page>

По умолчанию заголовок приложения содержит только заголовок приложения. Если вы хотите добавить другие компоненты пользовательского интерфейса, вам нужно переопределить его с помощью <Page.actionBar> . Затем внутри вы определяете вещи, которые вы хотите видеть в заголовке. Заголовок указывается с помощью <ActionBar> и установки в качестве атрибута title <ActionBar> title страницы.

Ниже мы использовали синтаксис усов для вывода значения app_title определенного в файле notes-page.js . Так вы выводите значения, которые привязаны к странице.

1
2
3
4
5
6
<Page.actionBar>
    <ActionBar title=»{{ app_title }}»>
        …
    
    </ActionBar>
</Page.actionBar>

Чтобы определить кнопки, сначала используйте <ActionBar.actionItems> в качестве родителя, и каждый <ActionItem> будет кнопками, которые вы хотите определить. Атрибут tap указывает функцию, которая будет выполняться при нажатии кнопки, а os.position и android.position — это позиции кнопки в iOS и Android.

Чтобы указать текст кнопки, вы можете использовать text атрибут <ActionItem> . Однако в настоящее время NativeScript не позволяет изменять цвет текста кнопки с помощью CSS. Вот почему вместо этого мы использовали <ActionItem.actionView> чтобы определить содержимое кнопки и установить ее цвет текста.

1
2
3
4
5
6
7
8
9
<ActionBar.actionItems>
  <ActionItem tap=»newNote» ios.position=»right» android.position=»actionBar»>
    <ActionItem.actionView>
        <StackLayout orientation=»horizontal»>
          <Label text=»New Item» color=»#fff» cssClass=»header-item» />
        </StackLayout>
    </ActionItem.actionView>
  </ActionItem>
</ActionBar.actionItems>

Далее идет фактическое содержание страницы. Вы можете расположить различные элементы, используя один или несколько контейнеров макета . Ниже мы использовали два доступных макета: StackLayout и GridLayout .

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

С другой стороны, GridLayout позволяет упорядочивать элементы в структуре таблицы. Если вы когда-либо использовали Bootstrap или другие CSS-фреймворки, это должно показаться вам естественным. GridLayout позволяет вам определять строки и столбцы, среди которых может быть размещен каждый компонент пользовательского интерфейса. Мы посмотрим, как это будет реализовано позже. А пока давайте перейдем к коду.

Сначала определим форму для создания новой заметки. Как и в HTML, вы можете определить такие атрибуты, как id и cssClass (эквивалентный атрибуту class HTML). Атрибут id прикрепляется к элементу, если вы хотите манипулировать им из кода. В нашем случае мы хотим оживить форму позже. cssClass используется для указания класса CSS, который вы будете использовать для cssClass элемента.

Внутри формы находится текстовое поле для ввода заголовка заметки, кнопка для прикрепления изображения, выбранное изображение и кнопка для сохранения заметки. Элемент изображения виден, только если attachment_img имеет истинное значение. Это будет иметь место, если изображение было ранее прикреплено.

1
2
3
4
5
6
<StackLayout id=»form» cssClass=»form-container»>
  <TextView text=»{{ item_title }}» hint=»Title» />
  <Button text=»Attach Image» cssClass=»link label» tap=»openCamera» />
  <Image src=»{{ attachment_img }}» id=»attachment_img» cssClass=»image» visibility=»{{ attachment_img ? ‘visible’ : ‘collapsed’ }}» />
  <Button text=»Save Note» tap=»saveNote» cssClass=»primary-button» />
</StackLayout>

Далее идет список, который показывает заметки, которые уже были добавлены пользователем. Списки создаются с помощью компонента ListView . Это принимает items в качестве обязательного атрибута. Значение может быть либо простым массивом, либо наблюдаемым массивом.

Если вам не нужно выполнять какую-либо форму обновления (например, удаление или обновление поля) для каждого элемента в массиве, подойдет простой массив JavaScript. В противном случае используйте наблюдаемый массив, который позволяет обновлять массив и автоматически отображать его в пользовательском интерфейсе. Мы рассмотрим, как определяется наблюдаемый массив позже.

Также обратите внимание, что ListView может иметь атрибут itemTap , который позволяет указать функцию, которая будет выполняться при нажатии элемента в ListView . Но в этом случае мы на самом деле не добавили его, так как нам не нужно выполнять никаких действий при нажатии на элемент.

1
2
3
<ListView items=»{{ notes }}» id=»list» visibility=»{{ showForm ? ‘collapsed’ : ‘visible’ }}»>
    …
</ListView>

Элементы в ListView могут быть определены с помощью <ListView.itemTemplate> . Здесь мы используем <GridLayout> для создания двух строк и двух столбцов. Атрибут columns используется для указания количества столбцов в каждой строке.

В этом случае *,* означает, что есть два столбца, каждый из которых занимает равное количество доступного пространства в текущей строке. Таким образом, если вся строка имеет общую ширину 300 пикселей, каждый столбец будет иметь ширину 150 пикселей. Таким образом, в основном каждый * представляет один столбец, и вы используете запятую для разделения каждого из них.

Атрибут rows работает аналогично, но контролирует объем пространства, используемого одной строкой. auto означает, что он будет занимать только то пространство, которое требуется дочерним элементам каждой строки.

После определения columns и rows в GridLayout вам все равно нужно указать, какой из его дочерних элементов принадлежит какой строке и столбцу. Первая строка содержит название элемента (1-й столбец) и кнопку удаления (2-й столбец). Вторая строка содержит изображение, которое было прикреплено к элементу (1-й столбец). Строка и столбцы указываются с использованием атрибутов row и col для каждого элемента.

Также обратите внимание на использование horizontalAlignment и verticalAlignment . Вы можете думать об этом как об эквиваленте NativeScript атрибута text-align HTML. Но вместо текста мы выравниваем компоненты пользовательского интерфейса. horizontalAlignment может иметь значение right , left , center или stretch , тогда как verticalAlignment может иметь значение top , bottom , center или stretch . Большинство из них говорят сами за себя, за исключением stretch , которое растягивается, чтобы занять доступное горизонтальное или вертикальное пространство.

В этом случае horizontalAlignment и verticalAlignment используются для центрирования изображения по горизонтали и вертикали внутри его столбца. И horizontalAlignment выравнивание используется на кнопке удаления, чтобы выровнять ее по крайней правой части второго столбца.

1
2
3
4
5
6
7
8
<ListView.itemTemplate>
  <GridLayout columns=»*,*» rows=»auto,auto» cssClass=»item»>
    <Label text=»{{ title }}» textWrap=»true» row=»0″ col=»0″ />
    <Image src=»{{ photo }}» horizontalAlignment=»center» verticalAlignment=»center» cssClass=»image» row=»1″ col=»0″ visibility=»{{ photo ? ‘visible’ : ‘collapsed’ }}» />
   
    <Button text=»delete» index=»{{ index }}» cssClass=»delete-button» tap=»deleteNote» row=»0″ col=»1″ horizontalAlignment=»right» loaded=»btnLoaded» />
  </GridLayout>
</ListView.itemTemplate>

Мы не указали атрибут itemTap для ListView . Вместо этого мы хотим прикрепить действие удаления, которое будет выполняться при каждом нажатии кнопки удаления внутри элемента списка. Каждый элемент имеет атрибут index , который мы передаем в качестве пользовательского атрибута для кнопки удаления. Это уникальный ключ, используемый для идентификации каждого элемента, чтобы мы могли легко обращаться к ним при необходимости.

Также обратите внимание на loaded атрибут. Так же, как <Page> имеет loaded атрибут, кнопки также могут иметь его. Позже вы увидите, как это используется.

Теперь мы готовы взглянуть на JavaScript, который заставляет все это работать. В этом разделе мы будем кодировать файл notes-page.js .

Сначала мы импортируем модули data/observable и data/observable-array . Это встроенные модули в NativeScript, которые позволяют нам создавать наблюдаемые объекты и массивы. Observables позволяют нам автоматически обновлять интерфейс всякий раз, когда обновляются эти объекты и массивы.

В нашем приложении pageArray используется для хранения массива заметок, а pageData — для его привязки к странице. pageData также служит общим контейнером для всех данных, которые мы хотим отобразить в пользовательском интерфейсе.

1
2
3
4
5
6
7
var Observable = require(«data/observable»);
var ObservableArray = require(«data/observable-array»);
 
var pageArray = new ObservableArray.ObservableArray();
var pageData = new Observable.Observable({
    notes: pageArray
});

Затем импортируйте все остальные модули, которые мы будем использовать на этой странице:

  • camera : для работы с камерой устройства.
  • view : для ссылки на конкретные элементы на странице. Думайте об этом как о эквиваленте document.getElementById в NativeScript.
  • ui/enums : глобальный словарь постоянных значений для всего, что связано с пользовательским интерфейсом.
  • ui/animation : для анимации элементов.
  • application-settings : для сохранения локальных данных.
  • file-system : для работы с файловой системой.
1
2
3
4
5
6
7
8
9
var cameraModule = require(«camera»);
var view = require(«ui/core/view»);
 
var uiEnums = require(«ui/enums»);
var animation = require(«ui/animation»);
 
var appSettings = require(«application-settings»);
 
var fs = require(«file-system»);

Затем инициализируйте значения переменных, которые будут использоваться во всем файле. page используется для хранения ссылки на текущую страницу, notesArr — копия массива текущих заметок на странице в виде простого массива, а current_index — начальное значение индекса, который используется в качестве уникального идентификатора для каждой заметки.

1
2
3
4
5
var page;
 
var notesArr = [];
 
var current_index = -1;

Функции становятся доступными в контексте страницы с помощью exports . Ранее в файле notes-page.xml вы видели, что pageLoaded() Функция выполняется при загрузке страницы.

1
2
3
exports.pageLoaded = function(args) {
    …
}

Внутри функции pageLoaded() мы начнем с получения ссылки на страницу. Затем мы показываем форму для создания новой заметки и получаем текущие сохраненные значения заголовка новой заметки и заметок из настроек приложения.

1
2
3
4
5
page = args.object;
pageData.set(‘showForm’, true);
 
var new_note_title = appSettings.getString(‘new_note_title’);
var notes = appSettings.getString(‘notes’);

Затем, все еще в функции pageLoaded() , проверьте, есть ли заметки, которые хранятся локально. Если нет, мы создаем массив заметок. Этот массив будет служить содержимым по умолчанию для новых пользователей приложения. Однако, если уже есть некоторые заметки, хранящиеся локально, мы конвертируем их в массив, а затем помещаем эти данные в наблюдаемый массив.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
if(!notes){
  notes = [
    {
      index: 0,
      title: ‘100 push ups’
    },
    {
      index: 1,
      title: ‘100 sit ups’
    },
    {
      index: 2,
      title: ‘100 squats’
    },
    {
      index: 3,
      title: ’10km running’
    }
  ];
 
}else{
  notes = JSON.parse(notes);
}
 
notesArr = notes;
if(!pageArray.length){
  for(var x = 0; x < notes.length; x++){
    current_index += 1;
    pageArray.push(notes[x]);
  }
}

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

1
2
pageData.set(‘item_title’, new_note_title);
args.object.bindingContext = pageData;

Анимируйте форму для создания новых заметок. Мы делаем это, используя функцию getViewById в view и передавая контекст (текущую страницу) в качестве первого аргумента и атрибут id назначенный элементу, которым вы хотите манипулировать.

Затем вызовите функцию animate . Это принимает объект, содержащий настройки анимации. Здесь мы хотим, чтобы форма скользила вниз на 160 пикселей от своего исходного положения в течение 800 миллисекунд.

1
2
3
4
view.getViewById(page, ‘form’).animate({
    translate: { x: 0, y: 160 },
    duration: 800,
});

Функция newNote() выполняется, когда пользователь нажимает на элемент действия « Новый элемент» в заголовке. Это скрывает и показывает новый элемент ListView и перемещает форму вверх или вниз в зависимости от текущего значения showForm .

Если showForm имеет значение true , что означает, что он отображается в данный момент, мы изменяем непрозрачность ListView на 1 в течение 400 миллисекунд, а затем сдвигаем форму вверх, чтобы скрыть ее. В противном случае мы скрываем ListView и сдвигаем форму вниз.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
exports.newNote = function() {
 
  var showForm = pageData.get(‘showForm’);
  var top_position = (showForm) ?
  var list_visibility = (showForm) ?
 
  view.getViewById(page, ‘list’).animate({
    opacity: list_visibility,
    duration: 400
  });
 
  view.getViewById(page, ‘form’).animate({
      translate: { x: 0, y: top_position },
      duration: 800,
  });
 
  pageData.set(‘showForm’, !showForm);
}

В файле notes-page.xml у нас есть loaded атрибут для удаления заметки. Это функция, которая выполняется, когда происходит это событие.

По умолчанию функция, назначенная itemTap в ListView , не будет выполняться, если кнопка определена внутри ListView . Это связано с тем, что NativeScript предполагает, что действия, выполняемые для каждого элемента списка, могут запускаться только с этих кнопок.

Приведенный ниже код является обходным решением для этого поведения по умолчанию. Это в основном убирает фокус на кнопке удаления, так что вы все равно можете выполнять функцию, когда пользователь нажимает на элемент ListView . В этом случае нам на самом деле не нужен этот код, поскольку мы не назначали какие-либо функции для нажатий элементов, но это хороший инструмент для работы со списками.

1
2
3
4
exports.btnLoaded = function (args) {
  var btn = args.object;
  btn.android.setFocusable(false);
}

Далее openCamera() функция openCamera() , которая выполняется, когда пользователь нажимает кнопку « Присоединить изображение» . Текущее состояние не поддерживается при использовании модуля камеры, поэтому нам нужно сначала сохранить название новой заметки в настройках приложения.

После этого мы можем запустить приложение камеры по умолчанию на устройстве, вызвав метод takePicture() . Этот метод принимает объект, содержащий настройки изображения. После того, как пользователь сделал снимок и нажал кнопку « Сохранить» в Android или кнопку « Использовать изображение» в iOS, обещание разрешается и выполняется функция обратного вызова, переданная в then() .

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

01
02
03
04
05
06
07
08
09
10
11
12
exports.openCamera = function() {
  appSettings.setString(‘new_note_title’, pageData.get(‘item_title’));
  cameraModule.takePicture({width: 300, height: 300, keepAspectRatio: true}).then(function(img) {
   
    var filepath = fs.path.join(fs.knownFolders.documents().path, «img_» + (new Date().getTime() / 1000) + «.jpg»);
    img.saveToFile(filepath, uiEnums.ImageFormat.jpeg);
     
    appSettings.setString(‘new_note_photo’, filepath);
    pageData.set(‘attachment_img’, filepath);
 
  });
}

Функция saveNote() выполняется, когда пользователь нажимает кнопку « Сохранить примечание» . Он получает текущее значение текстового поля заголовка заметки и путь к изображению, увеличивает current_index и помещает новый элемент в массив простых заметок и массив наблюдаемых заметок. Затем он сохраняет текущие заметки и current_index в настройках приложения, удаляет значения для новой заметки из настроек приложения, обновляет пользовательский интерфейс, чтобы форма отображала свое пустое состояние, и отображал список, скрывая при этом форму новой заметки.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
exports.saveNote = function() {
   
  var new_note_title = pageData.get(‘item_title’);
  var new_note_photo = pageData.get(‘attachment_img’);
 
  current_index += 1;
  var new_index = current_index;
  
  var new_item = {
    index: new_index,
    title: new_note_title,
    photo: new_note_photo,
    show_photo: false
  };
 
  notesArr.push(new_item);
  pageArray.push(new_item);
  
  appSettings.setString(‘notes’, JSON.stringify(notesArr));
  
  appSettings.setNumber(‘current_index’, new_index);
 
  appSettings.remove(‘new_note_title’);
  appSettings.remove(‘new_note_photo’);
 
  pageData.set(‘showForm’, false);
  pageData.set(‘item_title’, »);
  pageData.set(‘attachment_img’, null);
   
  view.getViewById(page, ‘list’).animate({
    opacity: 1,
    duration: 400
  });
 
  view.getViewById(page, ‘form’).animate({
      translate: { x: 0, y: -160 },
      duration: 800,
  });
 
}

Наконец, у нас есть deleteNote() которая выполняется, когда пользователь нажимает на кнопку удаления внутри элемента списка. Как вы уже видели из предыдущих функций, объект передается в качестве аргумента функциям, которые присоединены в качестве обработчика событий для определенного компонента. Этот объект имеет свойство object , которое относится к самому компоненту.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
exports.deleteNote = function(args){
   
  var target = args.object;
 
  var index_to_delete = notesArr.map(function(e) {
    return e.index;
  }).indexOf(target.index);
 
  notesArr.map(function(item, index){
 
    if(index == index_to_delete){
      notesArr.splice(index_to_delete, 1);
      pageArray.splice(index_to_delete, 1);
      return false;
    }
  });
 
  appSettings.setString(‘notes’, JSON.stringify(notesArr));
}

Откройте файл app.css и добавьте следующие глобальные стили:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
ActionBar {
    background-color: #b898ff;
    color: #fff;
}
 
.header-item {
    text-transform: uppercase;
}
 
.item {
    padding: 20;
    font-size: 20px;
}
 
.form-container {
    background-color: #fff;
    margin-top: -160px;
    padding: 20px;
    z-index: 10;
}
 
.label {
    font-size: 18px;
}
 
.link {
    text-align: left;
    background-color: transparent;
    color: #0275d8;
    padding: 5px;
    margin: 10px 0;
    text-transform: uppercase;
    font-size: 15px;
}
 
.image {
    width: 300;
    margin: 20 0;
}
 
.primary-button {
    padding: 5px;
    color: #fff;
    background-color: #0723bb;
    text-transform: uppercase;
}
 
.delete-button {
    font-size: 15px;
    background-color: #f50029;
    color: #fff;
}

Если вы хотите применить стили для конкретной страницы, вы также можете создать файл notes-page.css и определить там свои стили.

Вы можете запустить приложение на своем устройстве, выполнив tns run и затем платформу, на которой вы хотите развернуть. Вот пример для Android:

1
tns run android

Это автоматически устанавливает платформу Android для вас, если она еще не установлена, а затем запускает приложение на вашем устройстве после его установки. Как только приложение запустится, вы можете выполнить tns livesync android --watch чтобы автоматически обновлять приложение каждый раз, когда вы вносите изменения в исходные файлы.

Как и любая другая инфраструктура приложения, NativeScript позволяет разработчикам отлаживать свое приложение. Это делается с помощью инструментов разработчика Chrome. Есть два способа сделать это:

  1. Если приложение уже запущено, вы можете открыть новое окно терминала и выполнить tns debug android --start чтобы присоединить отладчик к запущенному в данный момент экземпляру приложения.
  2. Если у вас еще не запущено приложение, используйте tns debug android --debug-brk для создания экземпляра приложения с присоединенным к нему отладчиком.

Независимо от того, какой вариант вы выберете, в браузере Google Chrome откроется новая вкладка, которая позволяет отлаживать приложение, как обычное веб-приложение на JavaScript. Это означает, что вы действительно можете использовать console.log в своем исходном коде для проверки содержимого переменных, с которыми вы работаете.

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

Теперь, когда вы создали свое первое приложение NativeScript, пришло время еще больше расширить свои навыки, проверив, что еще можно сделать с NativeScript, и создав еще несколько приложений с ним.