Для создания многострочного поля ввода можно использовать компонент Web Viewer. Скопируйте текст в текстовой блок.
data:text/html,<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <html contenteditable="true">
Недостатком этого решения является то, что для использования введенного текста в нативной части его придётся каждый раз копировать из Web Viewer. Но к преимуществу относится то, что клавиатура не убирается после каждого ввода символа перевода строки, как это имеет место быть при вводе текста в многострочное поле ввода (на iPhone5).
Нативные средства не позволяют использовать HTML и CSS для оформления текста, в отличие от компонента Web Viewer.
data:text/html,<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <style>
.myClass{color:red}
</style>
<h3>Заголовок</h3> <div class="myClass">Красная строка</div>
В последних версиях такая возможность была отключена. В качестве альтернативы можно использовать следующий код:
data:text/html,<meta charset="utf-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0"/>
<dialog><div style="width:100%;text-align:center">Alert</div>888-88-88</dialog>
Ключевым моментом здесь является использование блока "create text with" (join) для корректной интерпретации строки, содержащей кавычки.
Данная задача часто возникает при работе с Firebase или WebApi, которые возвращают данные в формате JSON.
В Thunkable X существуют блоки для получения списка из текстовой строки с разделителями и для получения свойств объектов. Поэтому суть преобразования состоит в очистке исходной JSON-строки от лишних символов и приведение её к текстовой строке с разделителями.
Рассмотрим простой пример:
{ "key1":"data1", "key2":"data2", "key3":"data3" }
Для получения списка необходимо из этой строки удалить скобки { и }, а также кавычки. После этого строка превратится в пары значений, разделённые запятой, которую несложно превратить в список.
На практике общий алгоритм выглядит так:
1) Получить нужную JSON-строку
2) Очистить её от лишних символов и превратить во список
3) Создать цикл по списку, в теле которого выбрать из стоки нужные данные для отображения в ListViewer
В случае использования сложной структуры JSON, символ запятой буде разделять не только объекты, но и поля, по причине чего её не получится использовать в качестве разделителя записей. Перед очисткой данных необходимо создать новый разделитель записей, например, заменив "}," на "}#", где # - разделителем записей.
Из-за ошибки индексации списка (когда они начинаются от 0, а не от 1, как должно быть) блоки для получения и установки значений списка возвращают неверные значения. Для устранения этой ошибки можно использовать следующие блоки.
Средства для совместной работы в Thunkabke X отсутствуют, но есть возможность одновременно заходить в один и тот же аккаунт с разных рабочих мест. Это позволяет создать общий проект, который можно совместно обновлять. Проблема в том, что при одновременном редактировании проекта несколькими пользователями изменения будут сохранены только для одного из них, а все остальные пропадут. Выходом может служить последовательная работа над проектом, когда его редактирует один разработчик. Например, на первом экране совместного проекта создаётся надпись "Проект редактируется", под ним надпись с именем того, кто редактирует проект, а ещё ниже переключатель. При входе в проект редактор включает переключатель и указывает своё имя. Если кто-то откроет этот проект, то он увидит, что такой-то человек уже редактирует проект и нужно подождать своей очереди.
Более надёжным является подход, при котором выбирается руководитель группы (интегратор), которому остальные участники группы предоставляют доступ к отлаженным частям своих проектов, а он вручную объединяет их в окончательном приложении.
Прозрачность изменяется от 0 до 1.
Также возможно задать формате #rgb, #rgba, HSL (оттенок, насыщенность, яркость) или HSLA (c компонентой прозрачности), например:
#ff0
#f0f8
hsl(200, 100%, 50%)
hsla(200, 100%, 50%, 0.1)
Прозрачный цвет можно задать так:
rgba(0,0,0,0) или строкой "transparent".
Для преобразования строки в число необходимо строку присвоить переменной, а затем при помощи блока сложения произвести сложение этой переменной с 0.
Преобразование происходит от начала строки до первого символа, не относящегося к числу. Для нечисловой строки будет возвращено значение NaN (не число). В качестве числа можно использовать строку в научной форме, например, 2e2 (200).
Для этого используйте два блока отрицания not, например, not->not->1 (двойное отрицание используется для приведения значения к логическому типу). При этом только 0 даст значение false.
Общий алгоритм такой: над искомым значением производится некоторая операция. Если в результате получается некорректное значение, то предполагаемый тип не соответствует типу, для которого операция возвращает корректный результат.
Проверка на возможность преобразования значения к числовому типу.
Строгая проверка на число.
Для проверки на объект преобразуем значение в JSON и проверим наличие символа фигурной скобки.
Нежостаток данного способа.в том, что символ фигурной скобки можт присутствовать как часть строки. Другой спосоь состоит в использовании невидимого на экране компонента, тектовому блоку которого присваивается значение для проверки. Если передан объект, то в текстовом свойстве компонента будет строка [object Object].
Для проверки на строку можно использовать невидимый компонент, текстовому свойству которого присоединяется искомое через блок length of. Если передана не строка, то текстовое свойство компонента вернёт undefined.
Для копирования блока выполните следующие действия:
Копировать можно любые блоки, но следует учесть, что компоненты имеют локальную область видимости и не получится изменить их свойства из области редактирования блоков другого экрана.
Для отмены действий в редакторе блоков используйте Ctrl+Z или команду Undo контекстного меню, которое появляется при щелчке правой кнопкой мыши по рабочему полю редактора блоков.
При помощи данной команды невозможно отменить удаление компонентов.
На iOS перевод строки в компоненте Lable и др. осуществляется при помощи символа Юникода line separator (U+2028). В Android это не работает, но один из пользователей нашёл универсальное решение для получения символа \n.
К сожалению, в ListViewer на Android этот способ также не работает.
Существует несколько способов скрытия элементов:
В настоящее время Thunkable X не поддерживает Font Awesome, но при помощи символов Unicode можно:
Для этого необходимо открыть страницу с символами Юникода, найти нужный символ, скопировать его изображение и вставить в текстовое поле свойства компонента, текстовой блок, опцию списка и др. как показано ниже.
Вместо некторых значков в поле ввода может отображаться пустой пробельный символ.
Символы Юникода можно использовать, например, в элементах области списка List Viewer для имитации списка флажков или радиокнопок.
Для этого необходимо эмулировать ярлычковую навигацию при помощи кнопок:
Скриншот экрана iPhone.
Преимущество программной эмуляции навигации состоит в том, что она позволяет отслеживать переключение экранов, тогда как компоненты навигации сделать это не позволяют.
В простейшем случае табличное форматирование делается с использованием моноширинного шрифта, который можно использовать в компонентах Label и Input Text. Алгоритм выглядит очень просто. В функцию форматирования передаётся строка и ширина столбца в символах. Внутри функции производится вычитание длины строки из ширины столбца и полученное значение используется для создания в цикле строки пробелов, которая затем добавляется к исходной строке. Если длина строки больше ширины столбца, то она усекается до его величины.
Для создания пустых значений в блоках "create list width" и "join" открываем щелчком по пиктограмме шестерёнки контекстную панель настроек и удаляем из блока все опции.
Для сохранения изменений экранов можно использовать либо компоненты навигации, либо локальное хранилище.
При использовании компонентов навигации, экраны в них инициализируются один раз перед своим отображением. При использовании блока "navigate to" экран, на который происходит переход, инициализируется заново и ранее сделанные в нём изменения на сохраняются. Например, если в поле ввода была введена строка, а затем осуществлён переход на другой экран, то по возвращению на этот экран полее ввода будет иметь значение по умолчанию, заданное в поле свойства или блоке инициализации.
Для сохранения состояния экрана перед переходом на другой экран необходимо сохранить необходимые параметры в компоненте Local Storage, а в блоке "Screen Starts" - выгрузить их. При этом необходимо создать механизм инициализации по умолчанию, если запрашиваемые параметры в Local Storage отсутствуют.
Пока в Thunkable X нет блоков для позиционирования компонентов для этого можно использовать области с изменяемыми размерами. Изменение координаты Y спрайта производится изменением высоты компоновщика Column 16, а изменение координаты X - изменением ширины комноновщика Column 17, который вместе со спрайтом располагаются в компоновщике Row. Список возвращает строковые значения, которые при помощи математического блоков "round" преобразуются в числовые значения.
Если в редактор блоков поместить обработчики событий ползунка или таймера, то при перемещении ползунка или активации таймера будет происходит перерисовка изображения в компоненте Image и дёргание разметки, что делает работу с таким приложением невозможным. Избавиться от этого бага можно путём замены компонента Image на кнопку или Column. Для запрета нажатия на кнопку используется техника прозрачной крышки - создаём Column под размер изображения, в него добавляем кнопку с фоновым изображением, поверх которой размещаем ещё один прозрачный Column с абсолютным позиционированием.
Создание экрана-заставки в Thunkable X не является очевидной задачей. Без использования компонентов навигации вместо экрана-заставки с большой вероятностью получится экран-ловушка (как в одном из официальных демонстрационных примерах и примерах пользователей): при помощи свайп-жеста есть возможность вернуться на данный экран, после чего будет невозможно перейти с него ни на какой другой экран, если на нём не используется блок перехода на другой экран.
При помощи компонентов навигации экрана-ловушки можно избежать, но тогда пользователь может сколько угодно раз открывать экран-заставку, в результате чего он уже не будет заставкой. Единственно верным способом создания экрана-заставки является помещение всех экранов в компонент навигации Tab Navigator, у которого отключена функция перехода по свайп-жесту. Для навигации между экранами в этом случае необходимо использовать блоки "navigate to".
Для последовательного обновления данных в FireBase пользователи часто испольуют циклы с задержкой. Такой алгоритм работы с асинхронными блоками является ненадёжным и приводит к разным ошибкам. Перед очередным вызовом асинхронного блока нужно убедиться в том, что предыдущий вызов прошёл успешно, что реализуется при помощи рекурсии.
В данном примере не производится проверка успешности операции записи, но в реальные проекты необходимо добавлять проверку на отсутствие сообщения об ошибке в локальном блоке error.
Список переменных можно использовать для динамического создания данных и упростить обмен ими между экранами.
Кто-то может заметить, что это не список переменных, а обычный список данных. Да, но в концептуальном смысле это список переменных.
Для прослушивания интернет радио необходимо знать ссылку на поток вещания. Для этого в поисковике вбиваем, например, фразу "наше радио ссылка на поток вещания" и вскоре её находим в выдаче "Наше Радио (128 kb\ps) - http://nashe1.hostingradio.ru/nashe-128.mp3". Можно также воспользоваться каким-либо сервисом интернет радио, например, https://www.internet-radio.com. Открываем его, находим интересующую трансляцию и копируем ссылку m3u.
После получения ссылки на поток или плейлист указываем её в свойстве WebViewer.URL - в центре области Web Viewer отобразится простой проигрыватель и начнётся воспроизведение потока. Прервать его можно нажатием на кнопку паузы в проигрывателе, а выключить его посредством перезагрузки страницы, присвоив WebViewer.URL строку "about:blank". Для отсечения выходящего за границы сообщения об ошибке в компоненте Web Viewer установите свойство overflow = hidden.
Снимок экрана в режиме воспроизведения интернет радио.
Для простоты используем два списка, полученные путём копирования строк данных из Excel.
Функциональность данного базового примера можно увеличить на свой вкус. Можно, например, разделить все трансляции по музыкальным стилям и сначала выбирать стиль, а затем поток. Можно дать пользователю возможность самому добавлять новые трансляции - создать экран для ввода названия и ссылки на неё с добавлением в список избранных и последующим сохранением в локальном хранилище. Также можно данные хранить в AirTable, создать систему оценки рейтинга трансляции и др.
Предположим, в списке List находятся записи, состоящие из нескольких полей. Если в ListViewer отображаются уникальные значения ключевого поля из данного списка, то при выборе ListViewer не составит труда получить соответствующую ей запись в List, даже в случае использования сортировки ListViewer. Для этого достаточно сделать цикл по всем записям List и сравнить текущее значение ключевого поля с выбранным значением из ListViewer.
Если в ListViewer отображаются не уникальные значения и используется сортировка, то определить запись не представляется возможным, так как индексы в List и ListViewer из-за сортировки совпадать не будут. Для выхода из этой ситуации необходимо в опциях ListViewer сохранять полные записи. Но тогда в ListViewer будут отображаться значения нескольких полей и разделители между ними. В случае использования iOS при помощи символа разрыва строки можно спрятать поля записи (расположив их на второй неотображаемой строке), но на Android символы разрыва в ListViewer не работают! В таких случаях можно использовать отформатированный код записи, содержащий индекс записи в List, например:
Вася [001]
Маша [100]
Вася [034]
Теперь независимо от сортировки получится точно определить нужную запись по коду выбранной опции.
Для этого воспользуемся компонентом Web Viewer.
Для отправки sms вместо tel: укажите sms:, а для звонка по скайпу - skype:. Остальные возможности можно посмотреть в справке по URL-протоколам.
Вместо компонента Web Viewer можно использовать блок "open link". При использовании блока "open link" запускается внешний браузер, на экране которого будут отображёны данные ресурса по указанной ссылке.
Сделать звонок, отправить почтовое сообщение, открыть ссылку в браузере, отобразить адрес на карте или добавить событие на указанную дату можно и при помощи компонента TextInput. Для этого на вкладке дополнительных свойств поля ввода укажите тип обнаруживаемых данных в полях dataDetectorTypes для превращения их в ссылки.
В условиях отсутствия свойств видимости компонентов и некорректной работы редактора вида с позиционированием и отступами, решение данной задачи является настоящим экспериментированием с костылями.
Для создания кнопки и меню добавьте на экран два компонента Columns. В первом будет располагаться плавающая кнопка, а во втором - всплывающее меню.
Выбор режима позиционирования Columns производится на вкладке расширенных свойств Advanced панели свойств в категории Positioning, при открытии которой в поле Position нужно выбрать absolute. После этого выставляем нужные смещения в полях edgeOffsets и задаём значение в поле ZIndex, чтобы меню располагалось выше содержимого экрана..
Для скрытия элементов меню нужно в блоке инициализации экрана либо обнулять размеры контейнеров, их содержащих, либо обнулять размеры самих элементов меню, либо делать надписи и фон элементов меню прозрачными. Одного простого и работающего как на iOS, так и на Android решения здесь пока нет.
У кнопки есть свойство для указания в нём фонового изображения, но в Thunkable X это не работает. В качестве альтернативы можно воспользоваться либо html-кнопкой в Web Viewer, либо кнопкой, расположенной над компонентом изображения. Для этого поместите компоненты Image и Button в компоновщик Row с размером по содержимому, а свойство Position для изображения установите в absolute.
Создание пользовательского диалога основывается на абсолютном позиционировании контейнерного элемента, например, Column и инициализации у него свойства zIndex для отображения поверх других элементов на экране. На экран добавляем кнопку для открытия диалога и контейнер Column, внутрь которого добавляется List Viewer (для реализации List Picker).
Дополнение диалога тенью не так очевидно, как хотелось бы. Тень добавляется не контейнерному элементу Column, а рамке внутри него. Данная рамка создаётся при помощи пустого компонента Label с абсолютным позиционированием и относительными размерами 100% для того, чтобы она растянулась на всю область диалога. При этом List Viewer должен располагаться поверх Label.
Для реализации отмены диалога при нажатии за пределами его области расположите диалог над полноэкранной кнопкой (Button2), при нажатии на которую диалог будет закрываться.
Создайте файл geolocation.html со следующим кодом.
<script> if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(getLocation,getError); }else{ alert("Geolocation not supported"); } function getLocation(position){ var lat = position.coords.latitude; var lng = position.coords.longitude; alert("latitude: " + lat+"\nlongitude: "+ lng); } function getError(err){ alert("Error code: " + err.code); } </script>
Загрузите этот файл в проект и укажите его имя в свойстве Web Viewer.URL.