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

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

Меню

03.11.2017


5. Первый макет в Fuse

Создадим макет приложения с помощью UX Markup.

Сначала создаём фон (доска, на которой будут стикеры):

<App>
 <Rectangle Color="#EAEAEA" />
</App>

 

 

Затем добавляем иконки:

<App>
 <Image File="assets/flows.png" Width="30" Alignment="TopLeft" Margin="10" Color="#C4C4C4" />
 <Image File="assets/package.png" Width="30" Alignment="TopRight" Margin="10" Color="#C4C4C4" />
 <Rectangle Color="#EAEAEA" />
</App>

Обратите внимание, что я прописал иконки не после фона, а до него: в UX Markup очередь показа видимых объектов идентична слоям в графредакторе, т.е. чем выше объект в списке — тем ближе к зрителю.

Поэтому если бы я прописал иконки после фона — их просто не было бы видно.

Пометим для удобства свою «палитру слоёв», напоминая себе о знакомой очерёдности рендеринга объектов:

<App>
    <!-- Палитра слоёв -->
    <Image File="assets/flows.png" Width="30" Alignment="TopLeft" Margin="10" Color="#C4C4C4" />
    <Image File="assets/package.png" Width="30" Alignment="TopRight" Margin="10" Color="#C4C4C4" />
    <Rectangle Color="#EAEAEA" />
</App>

Обращаем внимание, что у иконок есть общие параметры (ширина, отступ и цвет). Их можно вынести в шаблонный объект (компонент), тем более что у этих объектов еще будут общие свойства.

Для этого я создам отдельный тег <Image> с общими для иконок свойствами и дам имя этому компоненту «icon»:

<App>
    <!-- Палитра слоёв -->
    <icon File="assets/flows.png" Alignment="TopLeft" />
    <icon File="assets/package.png" Alignment="TopRight" />
    <Rectangle Color="#EAEAEA" />

    <Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
</App>

Обратите внимание, что теги иконок обозначаются уже не Image, как раньше, а icon (строки 3 и 4), т.е. мы указали, что они — экземпляры (копии) созданного компонента (шаблона) Image на 7-ой строке.

Я уже упоминал об особенностях компонентов в кратком обзоре UX Markup.

У компонентов общей логики с графредакторами нет. Если Фотошоп или Фигма показывает шаблон-источник, на основе которого сделаны копии, то UX Markup работает скорее как CSS: мы прописали «правило»-как должен отображаться некий объект, а потом в HTML «присоединили» это правило селекторами class или id. Поэтому для аналогии с CSS можно вынести компоненты в начало документа, но обязательно помним, что такие конструкции в превью не рендерятся:

<App>

<!-- Шаблоны -->
    <Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
    
<!-- Палитра слоёв -->
    <icon File="assets/flows.png" Alignment="TopLeft" />
    <icon File="assets/package.png" Alignment="TopRight" />
    <Rectangle Color="#EAEAEA" />

</App>

Теперь я создам компонент кнопки, т.к. это одна из трёх основных кнопок приложения, которые «прибиты» к нижней границе:

Как создавать компоненты мы уже знаем, поэтому создаём компонент и прописываем как будет выглядеть экземпляр нашей кнопки (строка 5), а сам экземпляр улаживаем в нашу «палитру слоёв» (строка 10):

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<Panel ux:Class="button_new" Alignment="BottomCenter" Color="#fff" Width="220" Height="78" />
    
<!-- Палитра слоёв -->
    <icon File="assets/flows.png" Alignment="TopLeft" />
    <icon File="assets/package.png" Alignment="TopRight" />
    <button_new />
    <Rectangle Color="#EAEAEA" />

</App>

Но если облик наших кнопок схож, то текст на них разный («New flow», «New sticker», «Got my flow!»). Мы, конечно, можем на каждом экземпляре кнопки прописывать текст:

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<Panel ux:Class="button_new" Alignment="BottomCenter" Color="#fff" Width="220" Height="78" />
    
<!-- Палитра слоёв -->
    <icon File="assets/flows.png" Alignment="TopLeft" />
    <icon File="assets/package.png" Alignment="TopRight" />
    <button_new>
        <Text Value="New sticker" FontSize="24" Color="#157EFB" Alignment="Center" />
    </button_new>
    <Rectangle Color="#EAEAEA" />

</App>

Но это будет не совсем рационально.

Можно попробовать занести название кнопки в сам шаблон-компонент:

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<Panel ux:Class="button_new" Alignment="BottomCenter" Color="#fff" Width="220" Height="78">
    <Text Value="New sticker" FontSize="24" Color="#157EFB" Alignment="Center" />
</Panel>

<!-- Палитра слоёв -->
    <icon File="assets/flows.png" Alignment="TopLeft" />
    <icon File="assets/package.png" Alignment="TopRight" />
    <button_new />
    <Rectangle Color="#EAEAEA" />

</App>

Но так мы не сможем называть по-другому экземпляры этой кнопки.

Чтобы это было возможно — я выделю общее текстовое свойство для этих кнопок (её название), и попрошу компонент выдавать текст кнопки шаблонным форматированием, но уникальным содержанием для каждой кнопки:

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<Panel ux:Class="button_new" Alignment="BottomCenter" Color="#fff" Width="220" Height="78">
    <string ux:Property="button_name" />
    <Text Value="{ReadProperty button_name}" FontSize="24" Color="#157EFB" Alignment="Center" />
</Panel>

<!-- Палитра слоёв -->
    <icon File="assets/flows.png" Alignment="TopLeft" />
    <icon File="assets/package.png" Alignment="TopRight" />
    <button_new button_name="New sticker" />
    <Rectangle Color="#EAEAEA" />

</App>

Итак, давайте построчно разбираться в том, что я сделал.

В строке 6 у нашего уникального объекта button_new я создал своё уникальное свойство button_name. Структура тега создания нового свойства такова:

<тип_свойства ux:Property="имя_свойства" />

В нашем случае string обозначает строчный (текстовый) тип свойства, button_name — имя, которое я выбрал для свойства.

В 7-ой строке в свойстве Value тега Text стоят фигурные скобки { }, обозначающие динамическое значение, внутри которого дана команда считывать значение с определённого свойства (ReadProperty имя_свойства), что и происходит в 13-ой строке.

На данный момент картина приложения такая:

Я добавлю кнопке анимацию при клике, вернее, пропишу это в компоненте кнопки, т.к. подобное поведение предполагается для всех подобных кнопок:

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<Panel ux:Class="button_new" Alignment="BottomCenter" Color="#fff" Width="220" Height="78">
    <string ux:Property="button_name" />
    <Text Value="{ReadProperty button_name}" FontSize="24" Color="#157EFB" Alignment="Center" />
    <WhilePressed>
        <Change this.Color="#157EFB" Duration="0.1" 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" />
    <Rectangle Color="#EAEAEA" />

</App>

Как видите, для анимации в UX Markup ничего сложного нет: мы прописали определённое событие-последствие (строка 9, «измени цвет»), которое будет происходить при каком-то событии-причине (WhilePressed, «пока нажато»), т.е. пока объект нажат — измени его свойство на другое.

Но есть одна важная особенность: надо указать какой именно объект 🙂 Поэтому в 9-ой строке слово this обозначает, что надо менять тот объект, в рамках которого прописано это событие, т.е. он поменяет цвет самой панели. Иначе, если будет стоят просто Color, а не this.Color, машина не поймет цвет чего именно нам надо менять.

А если нам надо поменять еще и цвет текста «New sticker»? Т.е. надо прописать в программе Change Text.Color?

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<Panel ux:Class="button_new" Alignment="BottomCenter" Color="#fff" Width="220" Height="78">
    <string ux:Property="button_name" />
    <Text Value="{ReadProperty button_name}" FontSize="24" Color="#157EFB" Alignment="Center" />
    <WhilePressed>
        <Change this.Color="#157EFB" Duration="0.1" DurationBack="0.3" />
        <Change Text.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" />
    <Rectangle Color="#EAEAEA" />

</App>

Однако это не даст результата, и программа выдаст ошибку. Почему?

Потому что указано ошибочное имя. Text — это тег, а не имя нашего объекта, поэтому ошибка была бы и в том случае, если бы вместо this.color мы прописали казалось бы идентичное Panel.Color. Как решить эту задачу?

Надо шаблонному объекту Text дать его уникальное имя с помощью ux:Name (например, «link»), и тогда мы сможем указать программе, что при нажатии кнопки надо менять еще и цвет объекта link:

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<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" />
    <Rectangle Color="#EAEAEA" />

</App>

Отлично, теперь остаётся создать поток стикеров. Для этого я сначала создаю компонент стикера (строки 13-16), а потом располагаю его в «палитре слоёв» (строка 22):

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<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>
<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>

<!-- Палитра слоёв -->
    <icon File="assets/flows.png" Alignment="TopLeft" />
    <icon File="assets/package.png" Alignment="TopRight" />
    <button_new button_name="New sticker" />
    <sticker sticker_text="my note"/>
    <Rectangle Color="#EAEAEA" />

</App>

Обращаю внимание, что по аналогии с кнопкой, шаблонным является вид стикера (строка 13) и шаблонное форматирование текста (строка 15), само наполнение будет динамическим и выводится свойством sticker_text (строки 14 и 15).

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

Стикеров будет много, поэтому предполагается их вертикальный ряд на прокрутке. Для этого обёрнем наш стикер в три тега:

<App>

<!-- Шаблоны -->
<Image ux:Class="icon" Width="30" Margin="10" Color="#C4C4C4" />
<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>
<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>

<!-- Палитра слоёв -->
    <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="my note"/>
            </Each>
        </StackPanel>
    </ScrollView>
    <Rectangle Color="#EAEAEA" />

</App>

Each создаёт 20 стикеров, StackPanel выстраивает их в ряд, ScrollView оборачивает их в прокручиваемый контейнер. Теперь наша портянка готова.

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

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