При создании расширения можно использовать классы объектов App Inventor (встроенные или внутренние, как их ещё называют), Android и Java. Совместное их использование не вызывает сложностей за исключением одного момента. Некоторые классы виджетов App Inventor и Android имеют одинаковые имена, например:
com.google.appinventor.components.runtime.Button - класс кнопки App Inventor
android.widget.Button - класс кнопки Android
Для точного указания того, объект какого класса используется, необходимо тип объекта указывать полным названием пакета - android.widget.Button, а не Button.
Блочные функции могут принимать в качестве параметров или возвращать объекты App Inventor. Виджеты встроенных типов можно приводить к объектам Android для вызова методов, отсутствующих у них. Рассмотрим это на примере создания блока, изменяющего прозрачность любого подключенного к нему виджета встроенного типа. Код функции блока показан ниже.
AndroidViewComponent является родительским классом для виджетов. Его использование позволит присоединять к блоку объекты разных типов - кнопки, флажки, поля ввода и др. Если бы мы использовали тип Button, то тогда блок мог бы изменять прозрачность только кнопок.
Приведение объекта App Inventor к Android происходит в два действия:
Показанная функция блока хороша, но далеко не идеальна. Для вызова других методов Android придётся создавать похожие блоки. Например, для поворота виджета - блок поворота, для изменения ширины - блок изменения ширины и т.д. Если метод относится к родительскому классу View, то сделать это не так сложно, как в случае использования метода, характерного для определённого класса, что потребует постоянного отслеживания типов объектов и использования большого количества условных операторов. Выходом является программная генерация объектов и методов из строки, что можно осуществить при помощью рефлексии. Эта тема выходит за рамки данного материала, но её стоит изучить, если требуется придать App Inventor (и java-проектам) большей динамики.
Итак, при помощи универсальных блоков, созданных в расширении, можно добавить в разработку приложений App Inventor элементы текстового программирования. Это увеличит количество потенциально возможных ошибок - в тексте можно неправильно указать имя объекта, имя метода, типы параметров и др., но вместе с тем позволит на порядок сократить число блоков.
Полный код расширения показан ниже.
По аналогии с показанным примером добавьте в код функции блока для поворота виджета при помощи метода setRotation, информацию о котором можно найти в справке разработчика Android.
Добавим блок, создающий свойство alpha.
После установки расширения на панели свойств дизайнера появится поле ввода Alpha со значением по умолчанию 0.0, а в палитре блоков - блок для задания данного свойства. Для создания блока, возвращающего значение свойства, нужно создать ещё одну функцию, возвращающую это значение.
Преимущество встроенных объектов состоит в том, что они позволяют создавать экраны визуально, в компоновщики которых можно добавлять новые виджеты Android, отсутствующие среди встроенных объектов. В следующем примере показана функция блока, которая создаёт кнопку с фиксацией и добавляет её компоновщику App Inventor.
HVArrangement является родительским классом для всех встроенных компоновщиков Layout. Это позволит добавлять кнопку компоновщику любого вида - c вертикальным размещением, горизонтальным, а также их разновидностям со скроллингом.
В примере тип ToggleButton задан простым именем, так как среди встроенных классов App Inventor класса с таким именем нет, но было бы лучше указать полное имя пакета.
Параметром конструктора, создающего виджет Android, должен быть context, а при создании объекта встроенного типа - ComponentContainer. ComponentContainer является интерфейсом, который должны реализовать компоненты-контейнеры - компоненты, которые могут содержать в себе другие компоненты. К таким объектам относится главная форма, всегда имеющая имя Screen1 (компонент верхнего уровня) и компоновщики Layout. Необходимость указания контейнера при при создании виджетов встроенного типа приводит к тому, что они сразу добавляются указанному контейнеру. Нельзя сначала создать объект, а затем добавить его нужному контейнеру, как это можно сделать с виджетами Android.
Функции блоков, как было отмечено выше, могут принимать и возвращать только объекты App Inventor. А что делать, если нужно передать или вернуть объект Android? Для решения этой задачи нужно создать ассоциативный список объектов HashMap, в котором они будут доступны по своим уникальным именам-ключам. Это позволит передавать в функцию блока и возвращать из неё не объекты, а строки - имена нужных объектов. Этот список желательно сделать универсальным для хранения объектов Android и App Inventor. Для хранения виджетов список должен хранить объекты типа View. Если в него нужно добавить встроенный виджет, то добавляется не он, а его вид, например, Button.getView().
Функция блока для динамического создания экрана.
Если нужно после отображения динамического экрана вернуться к статическому Screen1, то вместо setContentView используем addContentView и removeView.
Для расположения виджетов на динамическом экране используется два контейнера - внейшний layMain и внутренний. Внешний layMain можно рассматривать в качестве подложки, прозрачность которой можно при необходимости изменять или делать полностью непрозрачной для имитации нового экрана.
Можно ли для более быстрой отладки интегрировать расширение в Android Studio? К сожалению, нет, но можно часть приложения, работающего с Android API, сначала отладить в ней, а затем перенести в файл расширения. При желании можно воспользоваться проектом App Inventor Java Bridge, позволяющий работать в Android Studio, но это несколько другой подход к разработке.