Как я создаю своё первое мобильное приложение

Процесс шел с 24 октября по 19 ноября 2017 года, суть приложения — создание заметок, инструмент — Fuse, мой уровень знаний — базовое знание HTML/CSS

Меню

04.11.2017


6. Динамический вывод текста в стикерах

Для «подключения» к стикерам их уникального содержимого нам надо ближе познакомиться со связыванием данных в UX Markup (data binding). Вкратце мы уже познакомились с этим аспектом, когда выводили динамическое название кнопки через {ReadProperty button_name}.

Для наглядности создам несколько текстовых объектов:

<App>

<StackPanel>
    <Text Value="Мой первый стикер" />
    <Text Value="Второй" />
    <Text Value="Третий" />
</StackPanel>

</App>

Я обернул их в StackPanel чтобы они не накладывались друг на друга.

Теперь создам источник данных, который будет хранить содержимое стикеров:

<App>

<Text Value="Содержимое стикеров" />

<StackPanel>
    <Text Value="Мой первый стикер" />
    <Text Value="Второй" />
    <Text Value="Третий" />
</StackPanel>

</App>

И подключу его содержимое к стикерам через уже знакомую команду {ReadProprty имя_считываемого_свойства}:

<App>

<Text Value="Содержимое стикеров" />

<StackPanel>
    <Text Value="{ReadProperty Value}" />
    <Text Value="{ReadProperty Value}" />
    <Text Value="{ReadProperty Value}" />
</StackPanel>

</App>

Однако ничего не произойдет, т.к. программа не понимает чьё именно Value надо считатывать.

Чтобы этого не происходило — создаём уникальное имя для объекта-источника (строка 3) и указываем конкретный путь для подключения (строки 6-8):

<App>

<Text ux:Name="storage" Value="Содержимое стикеров" />

<StackPanel>
    <Text Value="{ReadProperty storage.Value}" />
    <Text Value="{ReadProperty storage.Value}" />
    <Text Value="{ReadProperty storage.Value}" />
</StackPanel>

</App>

Эти операции связывания нам уже знакомы. Но как выводить уникальное содержимое для каждого стикера?

Стикеры представляют собой массив информации, поэтому берём на вооружение массив JavaScript и знакомимся с тем, как подключается js-код в UX Markup. Я уже упоминал, что в ux-документы можно подключать js-код.

Всё очень просто: открываем и закрываем соответствующий кусок js-кода соответствующим тегом:

<App>

<JavaScript>
// наш кусок js-кода
</JavaScript>

<Text ux:Name="storage" Value="Содержимое стикеров" />

<StackPanel>
    <Text Value="{ReadProperty storage.Value}" />
    <Text Value="{ReadProperty storage.Value}" />
    <Text Value="{ReadProperty storage.Value}" />
</StackPanel>

</App>

Теперь превратим объект-источник storage (строка 7) в массив данных для стикеров и удаляем ненужный код в значениях свойства Value, иначе программа будет выдавать ошибку, опять не понимая какие именно значения надо выдавать:

<App>

<JavaScript>
    var sticker_text = ["Мой первый стикер", "Второй", "Третий"];
</JavaScript>

<StackPanel>
    <Text Value="" />
    <Text Value="" />
    <Text Value="" />
</StackPanel>

</App>

Чтобы вывести в текстовые объекты данные из массива sticker_text, достаточно указать его в фигурных скобках в значении свойства Value, а в квадратных прописать порядковый номер ячейки массива (массив начинается с нуля, всё это базовые знания и операции в JS):

<App>

<JavaScript>
    var sticker_text = ["Мой первый стикер", "Второй", "Третий"];
</JavaScript>

<StackPanel>
    <Text Value="{sticker_text[0]}" />
    <Text Value="{sticker_text[1]}" />
    <Text Value="{sticker_text[2]}" />
</StackPanel>

</App>

Но ничего не произойдёт и программа выдаст ошибку о том, что не видит переменную sticker_text. Почему?

А потому, что js-код не будет виден до тех пор, пока мы не передадим нужные нам данные в тело программы с помощью команды module.exports, т.е. всё происходящее внутри тега JavaScript на 4 строке нашего примера будет работать отдельно от нашей программы (анонимно, за закрытыми дверями), пока мы не объявим программе, что существует некая новая переменная.

Это особенность UX Markup и очень важный момент, о котором надо помнить и который надо будет постоянно совершать, работая с js-кодом в ux-документах. Т.е. после того, как мы написали какой-то js-код внутри ux-документа, нам надо «афишировать» для программы данные этого кода с помощью команды module.exports.

В нашем случае это будет выглядеть следующим образом:

<App>

<JavaScript>

//невидимая часть js-кода
    var sticker_text = ["Мой первый стикер", "Второй", "Третий"];

//передаём и "публикуем" нужные нам данные из js-кода в программу
    module.exports = {
        sticker_text: sticker_text
    }

</JavaScript>

<StackPanel>
    <Text Value="{sticker_text[0]}" />
    <Text Value="{sticker_text[1]}" />
    <Text Value="{sticker_text[2]}" />
</StackPanel>

</App>

Чтобы еще лучше понять, что произошло, переименуем нашу «скрытую» переменную sticker_name в storage (строка 6), не забывая «опубликовать» её новое имя (строка 10):

<App>

<JavaScript>

//невидимая часть js-кода
    var storage = ["Мой первый стикер", "Второй", "Третий"];

//передаём и "публикуем" нужные нам данные из js-кода в программу
    module.exports = {
        sticker_text: storage
    }

</JavaScript>

<StackPanel>
<!-- связываем данные значений объектов -->
    <Text Value="{sticker_text[0]}" />
    <Text Value="{sticker_text[1]}" />
    <Text Value="{sticker_text[2]}" />
</StackPanel>

</App>

Обратите внимание на структуру module.exports. Выглядит эта команда как обычная js-функция, внутри которой мы приписываем «публичное» имя «скрытой» переменной. Имена могут быть идентичны, но я назвал их по-разному, чтобы вы лучше понимали суть работы с js-кодом в UX Markup.

Теперь программа без ошибок будет выдавать уникальное содержимое для каждого стикера, давая нам понимать как работает связывание данных и js-код в UX Markup. Применим эти знания в учебном проекте:

<App>

<JavaScript>
//невидимая часть js-кода
    var storage = ["Мой первый стикер", "Второй", "Третий"];
//передаём и "публикуем" нужные нам данные из js-кода в программу
    module.exports = {
        sticker_text: storage
    }
</JavaScript>

<!-- Шаблоны (компоненты) -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<Panel ux:Class="sticker" Width="220" Height="50" Margin="0,0,0,10" Padding="5,5,5,10" Color="#fff">  
    <string ux:Property="sticker_text" />
    <Text FontSize="16" Value="{ReadProperty sticker_text}" Color="#000" />
</Panel>
<Panel ux:Class="button_new" Alignment="BottomCenter" Color="#fff" Width="220" Height="78">
    <string ux:Property="button_name" />
    <Text ux:Name="link" Value="{ReadProperty button_name}" FontSize="24" Color="#157EFB" Alignment="Center" />
    <WhilePressed>
        <Change this.Color="#157EFB" Duration="0.1" DurationBack="0.3" />
        <Change link.Color="#fff" Duration="0.4" DurationBack="0.3" />
    </WhilePressed>
</Panel>

<!-- Палитра слоёв (экземпляры) -->
<icon File="assets/flows.png" Alignment="TopLeft" />
<icon File="assets/package.png" Alignment="TopRight" />
<button_new button_name="New sticker" />
<ScrollView>
    <StackPanel>
        <Each Count="20">
<!-- связываем данные значений объектов -->
            <sticker sticker_text="{sticker_text[0]}"/>
        </Each>
    </StackPanel>
</ScrollView>
<Rectangle Color="#EAEAEA" />

</App>

Итак, я проделал уже знакомые операции: создал массив данных на 5-ой строке, сделал «видимым» этот js-объект для ux-кода на 8-ой строке, увязал значение этого объекта с другим на 35-ой строке. Обратите внимание, что я указал конкретную ячейку массива [0], иначе программа опять не поймёт какое именно значение нам надо брать и выдаст ошибку.

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

Для этого в теге Each вместо свойства Count, где указывается конкретное количество повторяемых объектов, я прописываю свойство Items, которое будет динамически считывать количество ячеек в массиве, а в самом свойстве sticker_text я поставлю пустые фигурные скобки, чтобы по порядку и автоматически назначать стикеру ячейки массива:

<App>

<JavaScript>
//невидимая часть js-кода
    var storage = ["Мой первый стикер", "Второй", "Третий"];
//передаём и "публикуем" нужные нам данные из js-кода в программу
    module.exports = {
        sticker_text: storage
    }
</JavaScript>

<!-- Шаблоны (компоненты) -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<Panel ux:Class="sticker" Width="220" Height="50" Margin="0,0,0,10" Padding="5,5,5,10" Color="#fff">  
    <string ux:Property="sticker_text" />
    <Text FontSize="16" Value="{ReadProperty sticker_text}" Color="#000" />
</Panel>
<Panel ux:Class="button_new" Alignment="BottomCenter" Color="#fff" Width="220" Height="78">
    <string ux:Property="button_name" />
    <Text ux:Name="link" Value="{ReadProperty button_name}" FontSize="24" Color="#157EFB" Alignment="Center" />
    <WhilePressed>
        <Change this.Color="#157EFB" Duration="0.1" DurationBack="0.3" />
        <Change link.Color="#fff" Duration="0.4" DurationBack="0.3" />
    </WhilePressed>
</Panel>

<!-- Палитра слоёв (экземпляры) -->
<icon File="assets/flows.png" Alignment="TopLeft" />
<icon File="assets/package.png" Alignment="TopRight" />
<button_new button_name="New sticker" />
<ScrollView>
    <StackPanel>
<!-- связываем данные значений объектов -->
        <Each Items="{sticker_text}">
            <sticker sticker_text="{}"/>
        </Each>
    </StackPanel>
</ScrollView>
<Rectangle Color="#EAEAEA" />

</App>

Теперь приложение умеет динамически выводить содержимое стикеров из нашей «базы данных». Мне достаточно внести какие-то изменения в «базу данных» на 5-ой строке, и приложение автоматически отобразит новый стикер:

Скачать файл проекта

Становится очевидным, что основные операции в нашем приложении будут происходить с js-массивом (базой данных содержимого стикеров), поэтому теперь наше приложение должно уметь записывать новые данные в массив, редактировать и удалять их. Задачи ясны — двигаемся дальше!