DroidScript
DroidScript
инструменты для мобильной разработки

Thunkable X: создание пользовательских компонентов. Z-компоновка

Thunkable X  
19.11.2018

При создании пользовательских интерфейсов в среде Thunkable X возникает большая проблема, связанная с отсутствием компонентов с необходимой функциональностью - многострочного списка с изображениями, переключателя и ползунка с текстом, флажка, радиокнопки, компонентов выбора и т.п. Их можно было бы позаимствовать из web, но простого механизма обмена данными между WebViewer и app также нет. Остаётся единственный вариант - компоновать имеющиеся элементы друг с другом. Относительное позиционирование проще в реализации, но для качественного увеличения функциональности не обойтись без абсолютного позиционирования, использующегося для расположения элементов по глубине.

Хочу сразу обратить ваше внимание на то, что понятия пользовательского компонента в Thunkable X не существует и создать его невозможно. Под компонентом понимается независимая сущность, которая предназначена для повторного использования. В Thunkable X отсутствует операция копирования компонентов и под "пользовательским компонентом" здесь понимается компоновка базовых компонентов - кнопок, надписей, полей ввода и др., которую придётся вручную создавать заново при каждом её использовании независимо от того, находятся экземпляры на одном экране, в одном или разных проектах. Соответственно, в Thunkable X нет и понятия повторного использования чего-либо. Доступно только копирование блоков между экранами одного и того же проекта и создание копии всего проекта.

Относительное позиционирование компонентов

Под относительным позиционированием понимается расположение компонентов на одном уровне глубины без взаимного перекрытия их областей. При этом, как правило, они располагаются рядом друг с другом, но это необязательное условие. Отсюда следует очевидный вывод о том, что относительное позиционирование используется для получения компоновки с неперекрывающимися компонентами. Например, для создания ярлыка, который состоит из пиктограммы и надписи под ним, можно использовать компоновщик Column, в который добавить компонент изображения Image и текстовую область Label под ним.

Чем больше компонентов входит в компоновку и чем больше она требует настроек, тем сложнее создавать её экземпляры. Предположим, для настройки созданного нами ярлыка нужно изменить 15-20 значений свойств. Если нужно создать 10 таких ярлыков, то для этого придётся изменить 150-200 значений в полях свойств. Для изменения значения нужно позиционировать мышь, щёлкнуть кнопкой для фокусирования поля ввода, ввести при помощи клавиатуры значение и др. Добавив сюда то, что свойства разбросаны по категориям и двум вкладкам, получаем порядка 1000 элементарных действий, который нужно совершить для создания всего 10 простейших компоновок. Где-то ошиблись? Тогда придётся вручную внести правку во все копии компоновки!

Выход из этой ситуации один - создавать в Thunkable X максимально простые интерфейсы и уменьшать количество настроек для компоновок. Последнее осуществить непросто. Из-за давно существующего бага, для адекватного отображения разметки на Android необходимо для каждого использующегося компоновщика (Column, Row и, возможно, Screen) в проекте вручную задать внешние и внутренние отступы равными нулю. Если в проекте 10 экранов, на которых по 4 компоновщика, то придётся совершить 10*4*8 = 320 операций по изменению свойств для того, чтобы и на Android всё выглядело также хорошо, как и на iOS. По этой и другим причинам рекомендую разработку и отладку приложений проводить одновременно с использованием устройства iOS и Android. В противном случае может легко получится так, что на iPhone всё выглядит и работает замечательно, а для настройки проекта под Android требуется времени в 2-3 раза больше, чем это уже было затрачено под iOS. Ситуации, когда на Thunkable X люди днями не могут решить проблемы, не так и редки.

Функциональность компоновки при относительном позиционировании ограничена функциональностью входящих в её состав компонентов. Выше мы получили ярлык, состоящий из изображения и надписи, но этот элемент не может взаимодействовать с пользователем, потому что ни Column, ни Image, ни Label не имеют обработчиков событий. Для получения функциональность, которая отсутствует в базовых компонентах, необходимо использовать абсолютное позиционирование.

Абсолютное позиционирование компонентов (z-компоновка)

Данный подход используется в том случае, когда результирующая сборка компонентов должна иметь функциональность, превышающую функциональность отдельных компонентов. Наглядный пример - полноэкранная кнопка. У кнопки нет свойства абсолютного позиционирования, и, соответственно, невозможно создать полноэкранную кнопку с использованием только компонента Button. Но абсолютное позиционирование есть у компоновщика Column. Значит, необходимо Button вложить в полноэкранный Column с абсолютным позиционированием. При нажатии на такую кнопку будет изменяться её цвет. Если это нам не нужно, то фон кнопки задаётся прозрачным, а фон компоновщика - требуемым цветом.

Суть z-компоновки состоит в объединении свойств и функциональности отдельных компонентов таким образом, чтобы при их совместном использовании получить требуемую функциональность. Получается как бы гамбургер или слоёный пирог из компонентов. От компоновщика берётся возможность группировки элементов и фоновый цвет, от кнопки - возможность интерактивного взаимодействия с пользователем, от WebViewer - возможности HTML5, стилей CSS и т.д.

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

Создание компоновки нужной функциональности требует хорошее знание преимуществ и недостатков базовых компонентов и, возможно, навык программирования. Являются ли такие компоновки заменой нативных компонентов UI? Нет. Во многих случаях результат будет выглядеть ужасно. Но, если вы разрабатываете приложение для себя, то z-компоновка позволит вам уже сейчас пользоваться тем, что другим пользователям будет недоступно ещё многие месяцы, если не годы, потому что им придётся ждать того момента, когда разработчики реализуют необходимую функциональность. Характерный пример - область просмотра списка ListViewer. Базовая функциональность этого компонента позволяет получить только однострочный текстовой список, но при помощи z-компоновки можно получить многострочный список с пиктограммами и даже список карточек с заголовками и подвалами. Для получения такого списка в прокручивающийся компоновщик Column нужно поместить прозрачный непрокручивающийся ListViewer с нужным количеством строк, а под ним расположить WebViewer, в котором при помощи HTML и CSS создать разметку так, чтобы она в точности совпала с высотой одной или нескольких строк ListViewer. При прокрутке компоновщика информация в WebViewer и строки ListViewer будут прокручиваться одновременно, что нам и нужно. Проект с таким примером выглядит сложно и потребуется немало усилий для создания и настройки каждой его копии. Значительно упростить себе жизнь можно следующим образом - создать базовый проект, содержащий нужную сложную компоновку, а проект, в котором она требуется, создать из копии этого проекта. Тогда не придётся заново создавать всю компоновку в новом пустом проекте.

Компоненты нельзя копировать, а блоки можно. Для упрощения создания копий компоновки необходимо возможно большую часть по её настройке производить при помощи блоков.

Существенно упростить проект можно и путём создания одноэкранного приложения вместо многоэкранного.

Развитием z-компоновки является гибридная компоновка. Суть её состоит в том, чтобы весь дизайн (или большую его часть) сделать в WebViewer, а интерактивную часть реализовать при помощи прозрачных компонентов, наложенных на WebViewer сверху. Простой пример для размышления. Создадим в WebViewer html-страницу с кнопкой, при нажатии которой происходит некоторое действие. Мы не можем передать событие нажатия на кнопку или данные из WebViewer в app, но мы можем поверх этой кнопки расположить компонент Button и при нажатии на него реализовать нужное действие. На стороне WebViewer создаётся вид, а логика и данные реализуются на стороне app. В в примере создания списка, который был показан выше, как раз и реализован данный подход.

Thunkable X  
© 2016-2018 Александр Страшко